我在 C# 语言规范的 Variance Safety 一节中第一次遇到这些术语:输出安全、输入安全、输出不安全和输入不安全。我熟悉方差(协方差和逆变)的概念,它基本上是指使用一种类型代替另一种类型。
那么输出或输入安全的真正含义是什么?我们是在讨论泛型类型中的类型参数还是任何类型(引用或值)?
规范的这一部分——你指的是 C# 4 规范的第 13.1.3.1 节,也许你应该在问题的某个地方提到它——很不幸,我深表歉意。Mads 和我的意思很好,但我从来没有对规范的这一部分结果感到兴奋。
我们试图为 C# 规范提出“协变有效”、“逆变有效”和“不变有效”的更直观和易于理解的描述;最初的规范草案是用这些术语编写的,人们发现这些术语令人困惑。结果实际上并不太容易理解,并且包含一些错误。
我的建议是:如果您需要了解使变体接口有效或无效的确切规则,那么您应该阅读我关于此主题的注释:
http://blogs.msdn.com/b/ericlippert/archive/2009/12/03/exact-rules-for-variance-validity.aspx
这本质上是我在实现该功能时所做的注释的注释转录。这些注释比规范中的文本更详细,希望更清晰。
您可能还想阅读 CLI 规范中的相关部分;我的笔记直接基于对它的透彻阅读。
要真正回答您的问题:“输出不安全”和“输入不安全”背后的想法本质上是,如果您有:
interface I<in T>
{
T M();
}
然后T
不能安全地用于输出位置。假设我们允许这样做;这样做违反了类型安全:
class C : I<Animal>
{ public Animal M() { return new Giraffe(); } }
...
I<Animal> ia = new C<Animal>();
I<Tiger> it = ia; // Contravariant!
Tiger t = it.M(); // We just assigned a giraffe to a variable of type tiger.
这违反了类型安全,所以我们说这T
是“输出不安全”,因此这个接口是无效的,因为很明显T
是在输出位置使用的。同样对于“输入不安全”:
interface I<out T>
{
void M(T t);
}
你可以做一个I<Giraffe>
带长颈鹿的,把它转换成,I<Animal>
然后把老虎传给M
,这是不安全的。T
是输入不安全的,因此T
在输入位置使用的这个接口是无效的。