C#通用多态性[重复]
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#通用多态性[重复]相关的知识,希望对你有一定的参考价值。
这个问题在这里已有答案:
假设有一个像这样的基类叫做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) { }
TEST1
PaperCup A = new PaperCup();
Test01(A);
Test02(A);
以上代码工作正常。 A
实例可以传递给那两个函数,因为它是PaperCup
本身并且它继承了Cup
基类。
TEST2
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
而且你会得到一个不幸的运行时异常。使用泛型这不可能发生。
以上是关于C#通用多态性[重复]的主要内容,如果未能解决你的问题,请参考以下文章