虽然可以从基类/接口继承,但为什么不能声明List<>呢 使用相同的类/接口?

interface A
{ }

class B : A
{ }

class C : B
{ }

class Test
{
    static void Main(string[] args)
    {
        A a = new C(); // OK
        List<A> listOfA = new List<C>(); // compiler Error
    }
}

有别的办法吗?


当前回答

这是对BigJim的精彩回答的延伸。

在我的例子中,我有一个带有子字典的NodeBase类,我需要一种方法来从子字典中进行O(1)查询。我试图在Children的getter中返回一个私有字典字段,所以显然我想避免昂贵的复制/迭代。因此,我使用Bigjim的代码将Dictionary<whatever特定类型>转换为generic Dictionary<NodeBase>:

// Abstract parent class
public abstract class NodeBase
{
    public abstract IDictionary<string, NodeBase> Children { get; }
    ...
}

// Implementing child class
public class RealNode : NodeBase
{
    private Dictionary<string, RealNode> containedNodes;

    public override IDictionary<string, NodeBase> Children
    {
        // Using a modification of Bigjim's code to cast the Dictionary:
        return new IDictionary<string, NodeBase>().CastDictionary<string, RealNode, NodeBase>();
    }
    ...
}

这很有效。然而,我最终遇到了不相关的限制,并最终在基类中创建了一个抽象的FindChild()方法来代替它进行查找。事实证明,这从一开始就消除了对强制转换字典的需求。(出于我的目的,我可以用一个简单的IEnumerable替换它。)

所以你可能会问的问题(特别是当性能问题禁止你使用.Cast<>或.ConvertAll<>)是:

“我真的需要强制转换整个集合吗?或者我可以使用抽象方法来保存执行任务所需的特殊知识,从而避免直接访问集合吗?”

有时候最简单的解决方案就是最好的。

其他回答

实现这种工作的方法是遍历列表并强制转换元素。这可以使用ConvertAll:

List<A> listOfA = new List<C>().ConvertAll(x => (A)x);

你也可以使用Linq:

List<A> listOfA = new List<C>().Cast<A>().ToList();

可能会迟到。

转换为数组也可以完成这项工作。

main()
{
   List<Camel> camels = new List<Camel>();
   Reproducton(camels.ToArray());
}


public void Reproducton(Animal[] animals)
{
    foreach(var animal in animals.ToList())
    {
       var baby = animal.Reproduce();
    }
}

因为c#目前不允许这种类型的继承转换。

只能强制转换为只读列表。例如:

IEnumerable<A> enumOfA = new List<C>();//This works
IReadOnlyCollection<A> ro_colOfA = new List<C>();//This works
IReadOnlyList<A> ro_listOfA = new List<C>();//This works

对于支持保存元素的列表,不能这样做。原因是:

List<string> listString=new List<string>();
List<object> listObject=(List<object>)listString;//Assume that this is possible
listObject.Add(new object());

现在该做什么?记住listObject和listString实际上是同一个列表,所以listString现在有object元素,这应该是不可能的。

如果你使用IEnumerable代替,它将工作(至少在c# 4.0中,我没有尝试过以前的版本)。这只是一个集合,当然,它仍然是一个列表。

而不是——

List<A> listOfA = new List<C>(); // 编译器错误

在原代码的问题中,使用-

IEnumerable<A> listOfA = new List<C>();//编译错误-没有更多!:)