c# - 关于 C# 4.0 泛型协变的问题

标签 c# .net generics covariance

定义了这个接口(interface):

public interface IInputBoxService<out T> {
    bool ShowDialog();
    T Result { get; }
}

为什么下面的代码有效:

public class StringInputBoxService : IInputBoxService<string> {
    ...
}

...

IInputBoxService<object> service = new StringInputBoxService();

这不是吗?

public class IntegerInputBoxService : IInputBoxService<int> {
    ...
}

...

IInputBoxService<object> service = new IntegerInputBoxService();

int 是值类型有什么关系吗?如果是,我该如何避免这种情况?

谢谢

最佳答案

是的,这绝对与int有关是一个值类型。 C# 4 中的泛型变体仅适用于引用类型。这主要是因为引用始终具有相同的表示:引用只是一个引用,因此 CLR 可以对它知道是字符串引用的内容使用与对象引用相同的位。 CLR 可以确保代码安全,并使用只知道 IInputBoxService<object> 的 native 代码。当通过 IInputBoxService<string> - 从 Result 返回的值将在表示上兼容(如果存在这样的术语!)。

int => object必须有装箱等,所以你不会得到相同的代码 - 这基本上会混淆方差。

编辑:C# 4.0 规范在第 13.1.3.2 节中这样说:

The purpose of variance annotations is to provide for more lenient (but still type safe) conversions to interface and delegate types. To this end the definitions of implicit (§6.1) and explicit conversions (§6.2) make use of the notion of variance-convertibility, which is defined as follows: A type T is variance-convertible to a type T if T is either an interface or a delegate type declared with the variant type parameters T, and for each variant type parameter Xi one of the following holds:

  • Xi is covariant and an implicit reference or identity conversion exists from Ai to Bi

  • Xi is contravariant and an implicit reference or identity conversion exists from Bi to Ai

  • Xi is invariant and an identity conversion exists from Ai to Bi

这并没有让它变得非常明显,但基本上引用转换只存在于引用类型之间,这只留下身份转换(即从类型到自身)。

至于解决方法:我认为您基本上必须创建自己的包装器类。这可以很简单:

public class Wrapper<T>
{
    public T Value { get; private set; }
    public Wrapper(T value)
    {
        Value = value;
    }
}

虽然很讨厌:(

关于c# - 关于 C# 4.0 泛型协变的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2727242/

相关文章:

c# - XML Xpath 表达式

c# - 如何从 Google API 获取 JSON 数据并将其存储在变量中?

c# 前端 GUI 调用 linux C++ 函数

c# - NGEN x86 与 x64 与 .NET 可执行文件

.net - 单击一次更新版本重复问题

android - 如何解决泛型类的二级继承?

c# - 字典中不存在给定的键。哪把 key ?

c# - 什么时候应该使用 Environment.Exit 来终止控制台应用程序?

ios - 在 Swift 中使用泛型返回不同的约束类型

c# - Visual Studio 包和 VSIX 项目类型之间有什么区别?