Generics, Covariance/Contravariance, etc - c#

So I have some Java code that makes extensive use of generics that compiles just fine. I ported it over to C# as follows:
interface IFoo1 { }
interface IFoo2 { }
interface IBar<T, K>
where T : IFoo1
where K : IFoo2 {
List<T> GetFoo1s();
void AddAFoo1(T foo1);
List<K> GetFoo2s();
void AddAFoo2(K foo2);
}
interface IBlip<T>
where T : IBar<IFoo1, IFoo2> {
T DoBlip(string input);
void DoBlip2(T input);
}
interface IConverter<T, K>
where T : IBar<IFoo1, IFoo2>
where K : IBar<IFoo1, IFoo2> {
K Convert(T input);
}
class FooA1 : IFoo1 { }
class FooB1 : IFoo1 { }
class FooA2 : IFoo2 { }
class FooB2 : IFoo2 { }
class BarA : IBar<FooA1, FooA2> {
public List<FooA1> GetFoo1s() { return null; }
public void AddAFoo1(FooA1 foo1) { }
public List<FooA2> GetFoo2s() { return null; }
public void AddAFoo2(FooA2 foo2) { }
}
class BarB : IBar<FooB1, FooB2> {
public List<FooB1> GetFoo1s() { return null; }
public void AddAFoo1(FooB1 foo1) { }
public List<FooB2> GetFoo2s() { return null; }
public void AddAFoo2(FooB2 foo2) { }
}
class BlipA : IBlip<BarA> {
public BarA DoBlip(string input) { return null; }
public void DoBlip2(BarA input) { }
}
class BlipB : IBlip<BarB> {
public BarB DoBlip(string input) { return null; }
public void DoBlip2(BarB input) { }
}
class ConverterImplementation : IConverter<BarA, BarB> {
public BarB Convert(BarA input) {
return null;
}
}
When I compile this, it complains that, for example, with the ConverterImplementation, that BarA cannot be implicitly converted to IBar. I guess there's something that I'm fundamentally missing here. Could someone shed some light on it? Thanks.

Generic type parameters are by default neither contravariant nor covariant, but can be made one or the other via the "in" and "out" keywords.
In the case of IBar<T, K>, both type parameters are used as both inputs and outputs, so you cannot make them either contravariant or covariant. If you refactored it into two interfaces, one in which T is used only for input and K only for output, and one in which T is used only for output and K only for input, then you could make each type parameter covariant or contravariant based on its usage.

IBar is not a read only interface, therefore you may not achieve convariance in C#. You need to refactor and extract a read only interface, e.g. ReadOnlyBar, and do convariance on that interface. (disclaimer - not an expert on C#)
On the other hand, Java's wildcard can turn an interface to read-only and convariant interface, so IBar<? extends Animal> is read-only convariant, and IBar<? extends Tiger> is a subtype of it. That's cool and all, until your code is littered with lots of wildcards.

Related

Is it possible to define covariancy/contravariancy in generic interface in C++/CLI?

There is a nice article on covariancy and contravariancy in C#. Is it possible to implement such a covariant/contravariant interface in the C++/CLI?
Let's say that I have such a code in C#:
interface IMyGeneric<out T> { }
interface IMyOtherGeneric<out T> { }
class MyGeneric<T> : IMyGeneric<T> { }
class MyOtherGeneric<T> : IMyOtherGeneric<T> { }
void Foo(IMyGeneric<IMyOtherGeneric<string>> arg) { }
void Bar()
{
var mgs = new MyGeneric<MyOtherGeneric<string>>();
Foo(mgs);
}
How can I, or can I at all, implement it in C++/CLI?

Partial generic interface with type constraint

I need to create two partial interfaces. One with a constraint and the other without, like:
public partial interface IMyCuteInterface<T> where T : IEnumerable
{
void DoSomethingOnlyPossibleIfGenericIsIEnumerable();
}
public partial interface IMyCuteInterface<T>
{
void DoSomeStuff();
void DoSomeStuff2();
}
This is the implementation:
public class CuteInterfaceImplementation<T> : IMyCuteInterface<T>
{
private readonly T _element;
public CuteInterfaceImplementation(T element)
{
_element = element;
}
public void DoSomethingOnlyPossibleIfGenericIsIEnumerable(){}
public void DoSomeStuff(){}
public void DoSomeStuff2() { }
}
This is a static method to get this more dynamically:
public class CuteInterfaceImplementationBase
{
public static IMyCuteInterface<T> From<T>(T t)
{
return new CuteInterfaceImplementation<T>(t);
}
}
and this is the way I want to call it:
public static void Main(string[] args)
{
var mci = CuteInterfaceImplementationBase.From(args);
}
So, C# wants me to add the generic type constraint I added in the first interface to my CuteInterfaceImplementationBase.From<T> and my CuteInterfaceImplementation<T>-class.
What I want to achieve is: args could either be e.g. from type List<T> or from type int or something else. My target is, if args is from type IEnumerable<T> I want to add more functions (via the interface with the constraint) to CuteInterfaceImplementation-instance.
example:
if args is from type IEnumerable, this instance from CuteInterfaceImplementation has methods:
void DoSomethingOnlyPossibleIfGenericIsIEnumerable();
void DoSomeStuff();
void DoSomeStuff2();
if args is from type Foo or int (or any type that doesn't implement IEnumerable) I can use methods:
void DoSomeStuff();
void DoSomeStuff2();
means, DoSomethingOnlyPossibleIfGenericIsIEnumerable is not available.
But it seems, this is not possible, since I need to add the constraint to my implemented class. Any idea how to do this?
Not sure that this approach good idea, it violates the "I" in SOLID - interface
segregation
no client should be forced to depend on methods it does not use
You're using partial to split up two fundamentally different interfaces, you should have 2 different interface because they are different.
To answer your question:
If you're committed to a similar approach on the conditions of T, you could split the interfaces, move the "common logic" (which both interfaces use) to a base class and use the From<T> method to conditionally choose which implementation to create.
Something like this:
public partial interface IMyCuteInterface_WITHEnumerable<T> : IMyCuteInterface<T> where T : IEnumerable
{
void DoSomethingOnlyPossibleIfGenericIsIEnumerable();
}
public partial interface IMyCuteInterface<T>
{
void DoSomeStuff();
void DoSomeStuff2();
}
And then the implementations:
public class CuteInterfaceImplementation<T> : CuteInterfaceImplementation_COMMON<T>
{
public CuteInterfaceImplementation(T element) : base(element)
{
}
}
public class CuteInterfaceImplementation_COMMON<T> : IMyCuteInterface<T>
{
private readonly T _element;
public CuteInterfaceImplementation_COMMON(T element)
{
_element = element;
}
public void DoSomeStuff() { }
public void DoSomeStuff2() { }
}
public class CuteInterfaceImplementation_WITHEnumerable<T> : CuteInterfaceImplementation_COMMON<T>, IMyCuteInterface_WITHEnumerable<T> where T : IEnumerable
{
private readonly T _element;
public CuteInterfaceImplementation_WITHEnumerable(T element) : base(element)
{
_element = element;
}
public void DoSomethingOnlyPossibleIfGenericIsIEnumerable() { }
}
Finally your "static helper", which decides on the class to instantiate:
Unfortunately it's not possible in C# to conditionally instantiate the different classes because one expects T to be IEnumerable while the other doesn't. You can get around that using dynamic
public class CuteInterfaceImplementation_HELPER
{
public static IMyCuteInterface<T> From<T>(T t)
{
if (t is IEnumerable)
{
dynamic dyn = t;
return FromEnumerable(dyn);
}
else
{
return new CuteInterfaceImplementation<T>(t);
}
}
public static IMyCuteInterface<T> FromEnumerable<T>(T t) where T: IEnumerable
{
return new CuteInterfaceImplementation_WITHEnumerable<T>(t);
}
}

InvalidCastException on Generics

Coming from the Java world, programming with generics and C# is often a headache. Like this one:
interface ISomeObject { }
class SomeObjectA : ISomeObject { }
class SomeObjectB : ISomeObject { }
interface ISomething<T> where T : ISomeObject
{
T GetObject();
}
class SomethingA : ISomething<SomeObjectA>
{
public SomeObjectA GetObject() { return new SomeObjectA(); }
}
class SomethingB : ISomething<SomeObjectB>
{
public SomeObjectB GetObject() { return new SomeObjectB(); }
}
class SomeContainer
{
private ISomething<ISomeObject> Something;
public void SetSomething<T>(ISomething<T> s) where T : ISomeObject
{
Something = (ISomething<ISomeObject>)s;
}
}
class TestContainerSomething
{
static public void Test()
{
SomeContainer Container = new SomeContainer();
Container.SetSomething<SomeObjectA>(new SomethingA());
}
}
Which results into an InvalidCastException at Something = (ISomething<ISomeObject>)s;. In Java, this would work, and I could even use (if all else fails) the generics wildcard <?>. This is not possible in C#.
While this is just an example that I put together to explain the problematic, how can this exception be eliminated? The only main constraint is that SomeContainer cannot be a generic class
** Note ** : there are many questions about this, but none of them (that I could find) address a generic class member inside a non generic class.
** Update **
Inside the method SetSomething, I added these lines :
Console.WriteLine(s.GetType().IsSubclassOf(typeof(ISomething<SomeObjectA>)));
Console.WriteLine(s.GetType().ToString() + " : " + s.GetType().BaseType.ToString());
foreach (var i in s.GetType().GetInterfaces())
{
Console.WriteLine(i.ToString());
}
which to my surprise output
False
SomeThingA : System.Object
ISomething`1[SomeObjectA]
Is this why I get this exception?
Out keyword will be a fix, if your ISomething only have methods that return T
interface ISomething<out T> where T : ISomeObject
when creating a generic interface, you can specify whether there is an implicit conversion between interface instances that have different type arguments.
It is called Covariance and Contravariance
Eric Lippert have a good series of articles why we need to think about this, here interface variance is used
Here is my code, which works as expected for me
interface ISomeObject { }
class SomeObjectA : ISomeObject { }
class SomeObjectB : ISomeObject { }
interface ISomething<out T> where T : ISomeObject
{
T GetObject();
}
class SomethingA : ISomething<SomeObjectA>
{
public SomeObjectA GetObject() { return new SomeObjectA(); }
}
class SomethingB : ISomething<SomeObjectB>
{
public SomeObjectB GetObject() { return new SomeObjectB(); }
}
class SomeContainer
{
private ISomething<ISomeObject> Something;
public void SetSomething<T>(ISomething<T> s) where T : ISomeObject
{
Something = (ISomething<ISomeObject>)s;
}
}
class TestContainerSomething
{
static public void Test()
{
SomeContainer Container = new SomeContainer();
Container.SetSomething<SomeObjectA>(new SomethingA());
}
}
Sometimes it is useful to let a generic interface implement a non generic one to circumvent the missing <?>
interface ISomething
{
object GetObject();
}
interface ISomething<T> : ISomething
where T : ISomeObject
{
T GetObject();
}
public class SomeImplementation<T> : ISomething<T>
{
public T GetObject()
{
...
}
object ISomething.GetObject()
{
return this.GetObject(); // Calls non generic version
}
}
A collection can then be typed with the non generic interface
var list = new List<ISomething>();
list.Add(new SomeImplementation<string>());
list.Add(new SomeImplementation<int>());

Constructor requirements on generics parameter?

Looking at this question I started thinking about how to handle constructor requirements in C#.
Assume that I have:
T SomeMethod<T>(string s) : where T : MyInterface
{
return new T(s);
}
I want to set the requirement on T that it can be constructed out of a string, but as far as I know, constructor definitions are not allowed as part of interfaces. Is there a standard way to solve this?
Add an init method or a property to your interface,
public interface MyInterface
{
void Init(string s);
string S { get; set; }
}
T SomeMethod<T>(string s) : where T : MyInterface, new()
{
var t = new T();
t.Init(s);
var t = new T
{
S = s
};
return t;
}
As you can't specify arguments to constructor constraints
Another way is to dynamically invoke the constructor:
// Incomplete code: requires some error handling
T SomeMethod<T>(string s) : where T : MyInterface
{
return (T)Activator.CreateInstance(typeof(T), s);
}
The problem with that is that you lose type safety: if you try to use this with a MyInterface implementation that does not have a matching constructor, it will throw an exception.
If you want to make it required to have a constructor that takes a string input, you need to implement an abstract class:
public abstract class BaseClass<T>
{
public BaseClass<T>(string input)
{
DoSomething(input);
}
protected abstract void DoSomething(string input);
}
Your derived class then simply provides implementation for the abstract method and it can then pick up any interfaces it wants.
public class Sample<T> : BaseClass<T>, IMyInterface
{
public Sample<T>(string input)
: base(input)
{
}
protected override void DoSomething(string input)
{
}
public void MyInterfaceMethod()
{
}
}

C# Generics and Inheritance Problem

Hey, I'd like to know if what I'm trying to do is even possible? Comments in code should give and idea what I'm trying to achive :)
interface ITest<T> {
T t { get; }
bool DoTest();
}
public abstract class Test<T> : ITest<T> {
public Test (T nt) {
this.t = nt;
}
public Test () {
}
public T t {
get;
private set;
}
public abstract bool DoTest ();
}
public class STest : Test<string> {
public override bool DoTest () {
return true;
}
}
public class ITest : Test<int> {
public override bool DoTest () {
return true;
}
}
public class TestTest {
// I don't want to specify type here, I'd like TestTest to be able to have
// either a ITest or a STest. But for this class it should not matter.
// I just want to use DoTest() later on. No matter what
// specialication of Test this is.
Test myTest;
}
This might be a design problem, and I'd be willing to reconsider that if it is :)
I would suggest extracting the DoTest method to a super-interface, like this:
interface ITestable
{
bool DoTest();
}
interface ITest<T> : ITestable
{
T t { get; }
}
public class TestTest
{
ITestable myTest;
}
On an unrelated note, it is not recommended for class-names to begin with 'I' and for properties to begin with lower-case characters.
Place the DoTest() method in a non-generic ITest interface. Also, I would recommend making the ITest interface have a non-generic version of t. This is a quite common approach seen with interfaces like IEnumerable and IEnumerable<T>. The advantage is the non-generic version doesn't get less-capable and can hence can be fully leveraged in places where no actual type parameter can be supplied.
interface ITest
{
object t { get; }
bool DoTest();
}
interface ITest<T> : ITest
{
T t { get; }
}
Thanks to explicit implementation the unwanted non-generic or generic version (depending on the actual situation) can be hidden:
class STest : ITest<S>
{
public string t { get; private set; }
string ITest.t { get { return t; } }
public bool DoTest { ... }
}

Categories