简体   繁体   English

如何专门化继承的列表 <SuperClass> 到清单 <SubClass> 在C#中?

[英]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上搜索的具体术语是CovarianceContravariance

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM