问题
Consider a class hierarchy that looks as below. In essence, there is an abstract ComplexBase with some fields that are common to all classes. Then there is a ComplexClass derived from ComplexBase that, among other things, holds a collection of ComplexElements also derived from ComplexBase.
public abstract class ComplexBase {
internal abstract string Identifier { get; }
}
public abstract class ComplexClass<T> : ComplexBase where T : ComplexElement {
internal SortedList<string, T> Elements { get; set; }
}
public abstract class ComplexElement : ComplexBase { }
Implementations of the abstract classes are ComplexClassA and ComplexClassB. The ComplexElement collection of the former only contains instances of ComplexElementA and of the latter only ComplexElementB.
public class ComplexClassA : ComplexClass<ComplexElementA> {
public ComplexClassA() {
Elements = new SortedList<string, ComplexElementA>();
}
}
public class ComplexElementA : ComplexElement { }
public class ComplexClassB : ComplexClass<ComplexElementB> {
public ComplexClassB() {
Elements = new SortedList<string, ComplexElementB>();
}
}
public class ComplexElementB : ComplexElement { }
What I am struggling to understand is how to define a new class TheBigCollection holding various fields and methods, plus a collection of instances of both ComplexClassA and ComplexClassB. A non-working version might look like
public class TheBigCollection {
internal SortedList<string, ComplexClass> Classes { get; set; }
public TheBigCollection() {
Classes = new SortedList<string, ComplexClass>();
}
public void Add(string name, ComplexClass element) {
Classes.Add(name, element);
}
}
Of course this doesn't compile since ComplexClass is defined with a generic type.
My previous attempt was to use a concept of hiding the lists, but it turns out that this prevents me from accessing the lists of ComplexElements in instances of ComplexClassA or ComplexClassB that I retrieve from the list in TheBigCollection.
I learnt from my previous post that covariance could solve the problem, but I fail to understand how using IEnumerable—which is immutable—can be used to add new elements tho TheBigCollection's list of classes.
回答1:
I tried the following and it works fine.
internal interface IComplexClass
{
IDictionary<string, ComplexElement> Elements { get; }
}
public abstract class ComplexClass<T> : ComplexBase, IComplexClass where T : ComplexElement
{
internal SortedList<string, T> Elements { get; set; }
IDictionary<string, ComplexElement> IComplexClass.Elements
{
get { return (IDictionary<string, ComplexElement>)Elements; }
}
}
Now you could use IComplexClass in TheBigCollection.
来源:https://stackoverflow.com/questions/38629989/covariance-for-classes-with-list-members-in-c-sharp