在C#中,是否可以将List <Child>转换为List <Parent>?

Mat*_*hew 50 c# inheritance casting

我想做这样的事情:

List<Child> childList = new List<Child>();
...
List<Parent> parentList = childList;
Run Code Online (Sandbox Code Playgroud)

但是,因为parentList是Child的祖先List而不是直接祖先,所以我无法做到这一点.是否有解决方法(除了单独添加每个元素)?

rec*_*ive 74

使用LINQ:

List<Parent> parentList = childList.Cast<Parent>().ToList();
Run Code Online (Sandbox Code Playgroud)

文档 Cast<>()

  • 如果Child继承自Parent,那么您可以100%确定演员阵容无论如何都会有效. (4认同)
  • List <Parent> parentList = childList.OfType <Parent>().ToList(); 也适用,并且在您不太确定起始列表的内容的情况下是可取的. (3认同)
  • 注意,这会创建一个“ childList”的副本,就像@Andre Pena的not-using-LINQ版本一样。 (2认同)
  • lextm:不适用于列表。`List&lt;&gt;` 既不是协变也不是逆变。 (2认同)
  • @recursive true,因此您可以使用新的 Parent 对象列表进行迭代等。但是 List&lt;Parent&gt; 是一个新对象,而不是对原始对象的引用,因此,例如,如果删除其中一个元素,则不会修改原始 List&lt;Child&gt;。 (2认同)

Eri*_*ert 61

不允许直接进行转换,因为无法使其类型安全.如果你有长颈鹿的名单,并将它投入到动物名单中,那么你可以将老虎放入长颈鹿名单中!编译器不会阻止你,因为当然老虎可能会进入动物列表.编译器可以阻止你的唯一地方是不安全的转换.

在C#4中,我们将支持SAFE接口和使用引用类型参数化的委托类型的协方差和逆变.详情请见此处:

http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx

  • 更糟糕的是,如果编译器允许你这样做,你的列表最终会比预期的要小,因为老虎会吃掉一些长颈鹿. (126认同)

Ste*_*edy 5

早在2009年,埃里克(Eric)嘲笑我们,C#4中的情况将会改变。那么,我们今天站在哪里?

我的答案中使用的类可以在底部找到。为了使这更容易理解,我们将使用一个Mammal类为“父”,并CatDog类作为“孩子”。猫和狗都是哺乳动物,但是猫不是狗,狗也不是猫。

这仍然是不合法的,并且不能是:

List<Cat> cats = new List<Cat>();

List<Mammal> mammals = cats;
Run Code Online (Sandbox Code Playgroud)

为什么不?猫是哺乳动物,为什么我们不能将猫列表分配给List<Mammal>

因为,如果允许我们List<Cat>List<Mammal>变量中存储对a的引用,则可以编译以下代码以将一只狗添加到猫列表中:

mammals.Add(new Dog());
Run Code Online (Sandbox Code Playgroud)

我们绝对不允许这样!请记住,mammals仅是对的引用catsDogCat属于Cat对象列表,也没有业务涉及。

使用.NET Framework 4的开始,一些通用接口与声明的协变类型参数out通用修饰符在C#4.关键字介绍在这些接口被IEnumerable<T>这当然是由实施List<T>

这意味着我们现在可以将a List<Cat>转换为IEnumerable<Mammal>

IEnumerable<Mammal> mammalsEnumerable = cats;
Run Code Online (Sandbox Code Playgroud)

我们不能向其中添加新内容DogmammalsEnumerable因为它IEnumerable<out T>是一个“只读”接口,即它没有任何Add()方法,但是现在我们可以cats在任何IEnumerable<Mammal>可以使用a的地方使用它。例如,我们可以mammalsEnumerable与串联List<Dog>以返回新序列:

void Main()
{
    List<Cat> cats = new List<Cat> { new Cat() };
    IEnumerable<Mammal> mammalsEnumerable =
        AddDogs(cats); // AddDogs() takes an IEnumerable<Mammal>
    Console.WriteLine(mammalsEnumerable.Count()); // Output: 3. One cat, two dogs.
}

public IEnumerable<Mammal> AddDogs(IEnumerable<Mammal> parentSequence)
{
    List<Dog> dogs = new List<Dog> { new Dog(), new Dog() };
    return parentSequence.Concat(dogs);
}
Run Code Online (Sandbox Code Playgroud)

类定义:

public abstract class Mammal { }

public class Cat: Mammal { }

public class Dog : Mammal { }
Run Code Online (Sandbox Code Playgroud)