如何将继承的L​​ist <superclass>专门化为C#中的List <subclass>?</subclass> </superclass>

时间:2014-06-24 12:54:57

标签: c# .net inheritance collections

这听起来像是一个常见的问题,如果您的基类A具有类型为List<SuperClass>的公共属性并且您在类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; }
}

那么如何用新列表覆盖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;  
    }
}

2 个答案:

答案 0 :(得分:2)

你做不到。因为就目前而言,如果通过A接口插入SuperClass,B将失败,因为SuperClass无法插入到B的SubClass列表中。

您应该谷歌的具体字词为CovarianceContravariance

如果您将类限制为至少在基类中读取访问权限,则可以解决您的方案。那么你可以在你的B类中有两个只读属性,一个是专用的,一个不是专用的,但是返回专门的版本。

答案 1 :(得分:0)

我试一试。

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;
}

我使用IEnumerable。 当调用setter属性(类B)时,将IEnumerable<SuperClass>转换为List<SubClass>