为什么这个协方差声明可以编译

本文关键字:编译 声明 方差 为什么 | 更新日期: 2023-09-27 18:15:08

考虑这个接口:

interface Test<out T> where T : struct { }

编译时没有错误或警告。

在这个问题中讨论过,并在协方差和逆变常问问题中提到过:

只有当类型参数是引用类型时才支持方差

那么为什么上面的接口可以编译呢?在"out"关键字上失败(或至少发出警告)是有意义的。我想这个问题归结为——在上面的例子中使用out关键字是否有任何不同?

Update:这是一个误导行为的例子,可能会被不知情的开发人员忽略,他们看到了上面的接口:

typeof(IDummy).IsAssignableFrom(typeof(MyStruct)); // should return true
typeof(ITest<IDummy>).IsAssignableFrom(typeof(ITest<MyStruct>)); // returns false

如果编码员不知道方差对值类型不起作用,他们会期望第二行返回true -因为out关键字-但它永远不会。这正是促使我问这个问题的bug…


另一个可以编译但产生意外结果的示例:

ITest<MyStruct> foo = ...;
var casted = (ITest<IDummy>)foo;

我希望这能工作(不知道协方差对引用类型的限制),但它会导致System.InvalidCastException。

为什么这个协方差声明可以编译

在上面的例子中使用out关键字是否有任何不同?

不。您可以在声明中指定out,但是在处理该类型的特定实例时,您将无法实际利用它。

这个程序没有什么不能正常工作的,所以你本质上是要求编译器的特性请求禁止这种行为,因为它很可能表明开发人员有错误。对该请求的回应是(就像几乎任何其他功能请求一样),微软要么不认为这是一个选项,要么即使他们认为这是一个选项,也认为不值得花时间和精力去积极禁止这种行为。