[英]How to specialize an inherited List<SuperClass> to a List<SubClass> in C#?
This sounds like a common problem, so whats the best practice if you have a base class A with a public property of type List<SuperClass>
and you inherit that list in class B but want to use a more specialized type parameter for the list: 这听起来像是一个常见问题,因此,如果您有一个具有List<SuperClass>
类型的公共属性的基类A,并且您在类B中继承了该列表,但想为该列表使用一个更专门的类型参数,那么最佳实践是什么:
class SuperClass
{
public bool Flag;
}
class SubClass : SuperClass
{
public int Number;
}
class A
{
public List<SuperClass> Elements { get; }
}
class B : A
{
public List<SubClass> Elements { get; set; }
}
So how can in overwrite the Elements list with a new list, but still make sure it will be accessed if another class only knows A objects? 那么如何用新列表覆盖Elements列表,但是又确保如果另一个类仅知道A对象,则可以访问它呢?
class C
{
List<A> AList;
void FillList()
{
AList.Add(new B());
}
void DoSomething()
{
foreach (var a in AList)
forach(var super in a.Elements)
super.Flag = true;
}
}
You cannot. 你不能。 Because as it stands, if you insert a SuperClass through the A interface, B would fail, because SuperClass cannot be inserted into B's SubClass list. 因为按照现状,如果您通过A接口插入一个SuperClass,则B将失败,因为无法将SuperClass插入B的SubClass列表中。
The specific terms you should google are Covariance
and Contravariance
. 您应该在Google上搜索的具体术语是Covariance
和Contravariance
。
Your scenario can be solved if you restrict your classes to read access at least in the base class. 如果您限制类至少在基类中读取访问权限,则可以解决您的情况。 Then you could have two read-only properties in your B class, one specialized, one not specialized but returning the specialized version. 然后,您的B类中可能有两个只读属性,一个是专用的,一个不是专用的,但返回专用版本。
I gave it a try. 我试了一下。
class Program {
static void Main(string[] args) {
var c = new C();
c.FillList();
c.DoSomething();
Console.ReadKey();
}
}
class C {
List<A> AList;
public void FillList() {
AList = new List<A>();
var a = new A();
a.Elements = new List<SuperClass>() { new SubClass(), new SuperClass() };
AList.Add(a);
var b = new B();
b.Elements = new List<SubClass>() { new SubClass(), new SubClass() };
AList.Add(b);
}
public void DoSomething() {
foreach (var a in AList)
foreach (var super in a.Elements) {
super.Flag = true;
Console.WriteLine(super.GetName());
}
}
}
class SuperClass {
public bool Flag;
public virtual string GetName() { return "super"; }
}
class SubClass : SuperClass {
public SubClass() { }
public SubClass(SuperClass x) { }
public int Number;
public override string GetName() { return "sub"; }
}
class A {
public virtual IEnumerable<SuperClass> Elements {
get{
return elementList.AsEnumerable();
}
set {
elementList = value.ToList();
}
}
private List<SuperClass> elementList;
}
class B : A {
public override IEnumerable<SuperClass> Elements {
get {
return elementList.AsEnumerable();
}
set {
elementList = value.Aggregate(new List<SubClass>(),
(acc, x) => {
if (x is SubClass)
acc.Add((SubClass)x);
else
acc.Add(new SubClass(x));
return acc; });
}
}
private List<SubClass> elementList;
}
I use IEnumerable. 我使用IEnumerable。 And convert IEnumerable<SuperClass>
to List<SubClass>
when setter property (of class B) was called. 并在调用(B类的)setter属性时将IEnumerable<SuperClass>
转换为List<SubClass>
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.