I’m exposing an API through a facade with methods returning interface types, and I have run into an issue with generic lists and inheritance in C#/.NET 3.5.
I have two interfaces:
IMyList (implements IList<IMyItem>)
IMyItem
And three classes:
MyList (implements IMyList, extends List<MyItem>)
MyOtherList (implements IMyList, extends ObservableCollection<MyItem>)
MyItem (implements IMyItem)
But it doesn’t seem possible. How should I go about exposing only what is necessary, but still call the right implementations of the methods (that can vary for instance between MyList and MyOtherList)?
EDIT:
My facade is a factory looking something like this:
public static class Facade {
public static IMyList<IMyItem> CreateList() {
return new MyList<MyItem>();
}
public static IMyItem CreateItem() {
return new MyItem();
}
public static IConfiguration CreateConfiguration() {
return new Configuration();
}
}
Usage:
var list = Facade.CreateList();
list.DoSomethingOnChildren();
Now I’m expecting DoSomethingOnChildren() implemented in MyList to execute on a series of MyItem objects. If I was to change the method to return:
public static IMyList<IMyItem> CreateList() {
return new MyOtherList<MyOtherItem>();
}
I would expect DoSomethingOnChildren() implemented in MyOtherList to execute on a series of MyOtherItem objects.
Just because
MyItemimplementsIMyItemdoesn’t meanMyList<MyItem>implementsIMyList<IMyItem>. Put it this way, assume you had:IF this were allowed, it would cause tons of problems because it would let you do:
Since
Circleis also aShape. Some generic interfaces support co/contra-variance because the generic type parameter is used only in aninoroutfashion, because inIList<T>however, theTargument is used both ininandoutpositions, this makes it difficult, and C# doesn’t support it.So, you can’t convert the references, but you could load the members of an
MyList<MyItem>into anIMyList<IMyItem>through other means (LINQ, etc) and return a new instance of the list.If you wanted to support the two interface, but also allow a specific implementation, you could use explicit interface implementation.
UPDATE:
So, if you want to do something similar, you could do this instead. Have your interface return back the more generic implementation, then have your implementing classes have an explicit implementation to return only a generic implementation, and an overload for the specific implementation.
So something like:
You can only do this with explicit interface implementation, because you must still satisfy the original interface (must have same return type). But, it also allows us to say if used from the subclass reference, it can use the more specific method instead.