C# 无法从列表转换<;DerivedClass>;列出<;基类>;

C# 无法从列表转换<;DerivedClass>;列出<;基类>;,c#,C#,我试图将DerivedClass列表传递给一个函数,该函数获取BaseClass列表,但出现错误: cannot convert from 'System.Collections.Generic.List<ConsoleApplication1.DerivedClass>' to 'System.Collections.Generic.List<ConsoleApplication1.BaseClass>' 无法从转换 'System.Collections.Ge

我试图将
DerivedClass
列表传递给一个函数,该函数获取
BaseClass
列表,但出现错误:

cannot convert from 
'System.Collections.Generic.List<ConsoleApplication1.DerivedClass>' 
to 
'System.Collections.Generic.List<ConsoleApplication1.BaseClass>'
无法从转换
'System.Collections.Generic.List'
到
'System.Collections.Generic.List'
现在,我可以将我的
列表
转换为
列表
,但除非我理解编译器为什么不允许这样做,否则我不会感到舒服

我发现的解释只是说它在某种程度上违反了类型安全性,但我没有看到它。有人能帮我吗

编译器允许从
列表
转换到
列表
,有什么风险


这是我的SSCCE:

class Program
{
    public static void Main()
    {
        BaseClass bc = new DerivedClass(); // works fine
        List<BaseClass> bcl = new List<DerivedClass>(); // this line has an error

        doSomething(new List<DerivedClass>()); // this line has an error
    }

    public void doSomething(List<BaseClass> bc)
    {
        // do something with bc
    }
}

class BaseClass
{
}

class DerivedClass : BaseClass
{
}
类程序
{
公共静态void Main()
{
BaseClass bc=新的DerivedClass();//工作正常
List bcl=new List();//此行有错误
doSomething(new List());//此行有错误
}
公共无效剂量测定(列表bc)
{
//用bc做点什么
}
}
类基类
{
}
类派生类:基类
{
}

您描述的行为称为协方差–如果
A
B
,则
List
List

但是,对于像
List
这样的可变类型,这从根本上说是不安全的

如果这是可能的,该方法将能够将一个
新的OtherDerivedClass()
添加到一个实际上只能保存
DerivedClass
的列表中

协方差在不可变类型上是安全的,尽管.Net仅在接口和委托中支持协方差。
如果将
List
参数更改为
IEnumerable
,则该参数将起作用,因为
List
在variant中是
,而不是
co variant
,因此应更改为支持
co variant
IEnumerable
,该参数应起作用:

IEnumerable<BaseClass> bcl = new List<DerivedClass>();
public void doSomething(IEnumerable<BaseClass> bc)
{
    // do something with bc
}
IEnumerable bcl=new List();
公共无效剂量测定(IEnumerable bc)
{
//用bc做点什么
}
关于

的信息,如果你能写

List<BaseClass> bcl = new List<DerivedClass>(); 

将非DerivedClass的实例添加到列表中。

当您有一个从基类派生的类时,这些类的任何容器都不会自动派生。因此,您不能将
列表
强制转换为
列表

使用
.Cast()
创建一个新列表,其中每个对象都被强制转换回基类:

List<MyDerived> list1 = new List<MyDerived>();
List<MyBase> list2 = list1.Cast<MyBase>().ToList();
List list1=新列表();
List list2=list1.Cast().ToList();
请注意,这是一个新列表,而不是原始列表的强制转换版本,因此此新列表上的操作不会反映在原始列表上。但是,对包含对象的操作将反映

我发现的解释只是说它在某种程度上违反了类型安全性,但我没有看到它。编译器允许从
列表
转换到
列表
,有什么风险

这个问题几乎每天都有人问

列表
无法转换为
列表
,因为可以将蜥蜴放入动物列表中。
列表无法转换为
列表
,因为列表中可能已经有老虎

因此,
List
必须在T中保持不变


但是,
List
可以转换为
IEnumerable
(从C#4.0开始),因为在
IEnumerable
上没有添加蜥蜴的方法
IEnumerable
在T中是协变的。

我使用的解决方案是创建一个扩展类:

public static class myExtensionClass 
{
    public void doSomething<T>(List<BaseClass> bc) where T: BaseClass
    {
        // do something with bc
    }
}
公共静态类myExtensionClass
{
公共无效剂量仪(列表bc),其中T:基类
{
//用bc做点什么
}
}
它使用泛型,但当您调用它时,您不必指定类,因为您已经“告诉”编译器类型与扩展类相同

你可以这样称呼它:

List<DerivedClass> lst = new List<DerivedClass>();
lst.doSomething();
List lst=new List();
l.剂量测定法();

类从它的基派生,而不是
列表
列表
派生@TimSchmelter这是否意味着这种继承可能成为一种特性,其中
泛型
可以被视为从
泛型
派生?或者这样的功能会导致问题吗?只是没有这样实现@蒂姆施梅尔特:不;这样做是不可能的。@SamIam:您应该先将其实例化为一个
列表
。@SamIam:不;您正试图传递一个
列表
。传递一个包含
派生的
列表
会很好。因此,如果我在传递前将
列表
转换为
列表
,那可以吗?@SamIam:不可以。关键是将
列表
转换为
列表
,从根本上说是不安全的。如果您首先创建一个
列表
,它会起作用。@SamIam:SLaks解释得很好:如果您可以将
列表
强制转换为
列表
,那么理论上您可以将
其他派生的
的实例添加到该列表中(因为该列表是可变的)。但是它被实例化为一个
列表
,如果您试图手动将其转换回
列表
,您将得到一个
列表
,其中包含一个
其他派生的
。从.Net 4.5开始,如果方法需要随机访问集合元素,也可以使用
IReadOnlyList
。+1一个简单的动物学解释解释了这一切。(IEnumerable上没有添加蜥蜴-->的方法,我会检查以防万一;))我觉得自己很笨。。。长颈鹿似乎很明显,但为什么你不能把哺乳动物传给能对付动物的东西,仅仅因为它也能对付非哺乳动物呢?@MGOwen:你有一个哺乳动物的列表。你决定把它当作一个动物列表。你把一只蜥蜴列入动物名单。但它实际上是一个哺乳动物的列表。现在你有了一个包含蜥蜴的哺乳动物列表,违反了哺乳动物列表中只有mam的预期
List<DerivedClass> lst = new List<DerivedClass>();
lst.doSomething();