This question already has answers here:
C# variance problem: Assigning List<Derived> as List<Base>
(5个答案)
Covariance and IList
(4个答案)
去年关闭。
假设有一个像
并假设存在
并假设Main类中有两种方法。
测试1
上面的代码工作正常。可以将
测试2
上面的代码仍然可以正常工作。尽管
但是泛型!
让我们看看以下方法。
并且下面的该试验将在两个方法调用处失败。
简单问题
为什么当采用
然后,可能会发生以下情况:
您刚刚在塑料杯列表中插入了一个纸杯。那似乎不对。
您要问的是generic type variance。
C#确实允许在接口和委托中使用泛型类型差异,但只有在编译器可以确保其安全性时才允许使用。
例如
有趣的是,由于C#诞生时出于“支持其他现有语言功能”的原因,数组也支持类型差异,但它完全被破坏了。对于数组,这是完全合法的:
并且您将得到一个不幸的运行时异常。使用泛型,这不可能发生。
(5个答案)
Covariance and IList
(4个答案)
去年关闭。
假设有一个像
Cup
这样的基类:public abstract class Cup { }
并假设存在
PaperCup
继承Cup
和PlasticCup
继承PaperCup
类的情况。public class PlasticCup : PaperCup { }
public class PaperCup : Cup { }
并假设Main类中有两种方法。
static void Test01 (PaperCup cup) { }
static void Test02 (Cup cup) { }
测试1
PaperCup A = new PaperCup();
Test01(A);
Test02(A);
上面的代码工作正常。可以将
A
实例传递到这两个函数中,因为它是PaperCup
本身,并且是Cup
基类的继承。测试2
PlasticCup B = new PlasticCup();
Test01(B);
Test02(B);
上面的代码仍然可以正常工作。尽管
B
实例是PlasticCup
,但也可以被函数使用,但它继承于PaperCup
,并且最终从Cup
派生。但是泛型!
让我们看看以下方法。
static void Test010 (IList<PaperCup> cup) { }
static void Test011(IList<PlasticCup> cup) { }
static void Test012(IList<Cup> cup) { }
并且下面的该试验将在两个方法调用处失败。
IList<PlasticCup> BB = new List<PlasticCup>();
Test010(BB); // Fail CS1503 Compiler Error
Test011(BB);
Test012(BB); // Fail CS1503 Compiler Error
简单问题
为什么当采用
Generic
时无法将派生类型传递给这些函数?因为C#是OOP语言,它不应该工作吗? 最佳答案
好吧,想象一下允许以下情况:
IList<Cup> plasticCups = new List<PlasticCup>();
然后,可能会发生以下情况:
plasticCups.Add(new PaperCup()); //ouch!
您刚刚在塑料杯列表中插入了一个纸杯。那似乎不对。
您要问的是generic type variance。
IList<T>
在T
中是不变的,因为任何其他选项(协变或逆变)都不安全。C#确实允许在接口和委托中使用泛型类型差异,但只有在编译器可以确保其安全性时才允许使用。
例如
IEnumerable<out T>
在T
中是协变的,因为您不能在IEnumerable<PlasticCup>
中插入纸杯(规则是,实际上绝对不要将T
类型用作方法参数),因此以下内容很完美安全,可以编译:IEnumerable<Cup> plasticCups = Enumerable.Empty<PlasticCup>();
有趣的是,由于C#诞生时出于“支持其他现有语言功能”的原因,数组也支持类型差异,但它完全被破坏了。对于数组,这是完全合法的:
object[] strings = new string[] { .... }
strings[0] = new object(); //oh oh
并且您将得到一个不幸的运行时异常。使用泛型,这不可能发生。
09-26 08:16