你能用隐式转换满足generics约束吗?

鉴于以下类型:

class A { } class B { public static implicit operator A(B me) { return new A(); } } class Test where T : A { } 

我试过了

 var b = new Test(); 

并期望它失败,它做到了。 但错误信息是

类型’B’不能用作generics类型或方法’Test’中的类型参数’T’。 没有从’B’到’A’的隐式引用转换。

但是有从B到A的隐式引用转换。这只是一个奇怪的消息吗? 亚当罗宾逊的答案显示, 没有隐含的参考转换。 消息是正确的。

请注意, MSDN说:

其中T :(基类名) – 类型参数必须是或从指定的基类派生。

这解释了为什么不允许它,因为B不是从A派生A

不,你想做什么是不可能的。 隐式引用转换与隐式类型转换不同。 您的代码定义了一个隐式类型转换,您可以在其中执行以下操作:

 B foo = new B(); A bar = foo; 

但请注意, foobar现在包含不同的引用。 隐式类型转换创建一个A实例,应该(按照惯例)在逻辑上等同于foo 。 但关键是它是一个不同的参考。

引用转换将是引用本身不会更改的位置,这意味着有问题的类型必须inheritance(对于类)或实现(对于接口)所讨论的类型。 如果我这样做:

 class A { } class B : A { } 

那么我上面的代码现在将在foobar保存相同的引用。 这就是隐式引用转换的含义。 相反, 明确的引用转换将是向下转换,如下所示:

 A foo = new B(); B bar = (B)foo; 

同样,引用是相同的,但演员是明确的。

因此,简而言之,MSDN文档更清晰但不太精确。

这是不可能的。

隐式转换与类型等价不同。 仅仅因为类型可以转换为另一种类型并不意味着它是第二种类型的特定forms。 因此,它不适用于通用约束。

这非常有意义 – 想想编译器在下面会做什么:

 class A { public void Foo(); } class B { public static implicit operator A(B me) { return new A(); } } 

现在,说你有:

 public void Bar(T obj) where T : A { obj.Foo(); obj.Foo(); obj.Foo(); } 

为了使这个工作与转换(即:允许调用Bar(new B()) ) – 你必须在该方法内构造一个NEW对象实例,因为Foo没有在B上定义。这将是非常的意外,并可能导致一些非常难以发现的错误。 在上面,每次方法调用都应该进行转换操作吗? 它应该发生一次,并且编译器做一些技巧使其工作? 虽然可以想象如何处理这个问题,但没有一种方法是明确的……

其他人已经覆盖了它,但我想我会粘贴一些规格的东西

有效内容的完整列表在c#语言规范的第6.1.6章中。 关键部分是最后一段说:

隐式或显式的引用转换永远不会更改要转换的对象的引用标识。 换句话说,虽然引用转换可能会更改引用的类型,但它永远不会更改所引用对象的类型或值。

完整的转化列表如下:

隐式引用转换是:

  • 从任何引用类型到对象和动态。
  • 从任何类型S到任何类型类型T,只要S来自T.
  • 从任何类型S到任何接口类型T,只要S实现T.
  • 从任何接口类型S到任何接口类型T,只要S来自T.
  • 从具有元素类型SE的数组类型S到具有元素类型TE的数组类型T,提供以下所有条件:
    • S和T仅在元素类型上有所不同。 换句话说,S和T具有相同的维数。
    • SE和TE都是参考类型。
    • 从SE到TE存在隐式引用转换。
  • 从任何数组类型到System.Array及其实现的接口。
  • 从一维数组类型S []到System.Collections.Generic.IList及其基接口,前提是存在从S到T的隐式标识或引用转换。
  • 从任何委托类型到System.Delegate及其实现的接口。
  • 从null文字到任何引用类型。
  • 从任何引用类型到引用类型T,如果它具有隐式标识或引用转换为引用类型T0,则T0具有到T的标识转换。
  • 从任何引用类型到接口或委托类型T,如果它具有隐式标识或引用转换到接口或委托类型T0和T0是方差可转换(第13.1.3.2节)到T.
  • 涉及已知为引用类型的类型参数的隐式转换。 有关涉及类型参数的隐式转换的更多详细信息,请参见第6.1.10节。

在您的示例代码中, B不是从A派生A 尝试

 class B : A { public static implicit operator A(B me) { return new A(); } } 

不,这不是一个奇怪的消息。 “隐式引用转换”(规范部分6.1.6。)与“用户定义的隐式转换”(第6.1.10节)不同,这就是您所拥有的。

引用转换意味着您可以将对给定对象的引用从一种类型转换为另一种类型(“引用转换…永远不会更改正在转换的对象的引用标识”)。

用户定义的隐式转换可以(就像你一样)返回一个新的不同对象。