I have a problem with generics in C# I hope you can help me out with.
public interface IElement { }
public interface IProvider<T> where T : IElement {
IEnumerable<T> Provide();
}
So far it’s pretty simple. I want the providers to return enumerables of specific elements.
A specific implementation of the interfaces is as follows:
public class MyElement : IElement { }
public class MyProvider : IProvider<MyElement> {
public IEnumerable<MyElement> Provide() {
[...]
}
}
But the problem comes now when I want to use it. This does not compile because it cannot implicitly convert MyProvider into IProvider<IElement>:
IProvider<IElement> provider = new MyProvider();
I have to do a cast to IProvider<IElement> despite MyProvider is an IProvider<MyElement> and MyElement is an IElement. I could avoid the cast by making MyProvider also implement IProvider<MyElement>, but why does it not resolve the hierarchy in the type parameter?
EDIT: As per Thomas’s suggestion, we can make it covariant in T. But what if there are other methods like below where there are arguments of type T?
public interface IProvider<T> where T : IElement {
IEnumerable<T> Provide();
void Add(T t);
}
If you only use the reference to
IProvider<IElement>to access methods that haveTin an output position, you could segregate the interface into two (please find better names for them, likeISink<in T>for the contravariant one):Your class implements both:
But now you use the covariant interface when you need to upcast:
Alternatively, your interface can inherit from both:
And your class implements it: