当T是接口时,为什么我的演员操作员从T到SomeStruct <T>不工作?

Cra*_*ney 4 c# generics interface operator-overloading type-conversion

当我尝试使用从接口类型到泛型结构类型的用户定义的强制转换操作符时,我收到一个编译错误,指出该类型无法转换:

public interface J { }
public struct S<T> {
    public static explicit operator S<T>(T value) {
        return new S<T>();
    }
}
public static class C {
    public static S<J> Test(J j) {
        return (S<J>)j; // <- error: cannot convert type 'J' to type 'S<J>'
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,如果J是一个类,转换将起作用.

关于转换为类有一个类似的问题,答案是派生类可能实现接口并且在是否应该使用用户定义的转换时产生歧义.但是对于结构体,可能没有派生类型,编译器知道我的结构体没有实现J.

也许是为了避免意外的语义变化,因为接口实现了新的接口?也许这只是偶然的?也许我犯了一个天真的错误?从规范中引用的内容会非常棒,但我真的很喜欢它首先设计的原因.

Str*_*ior 6

好吧,系统无法进行实际演员,因为S<J>没有实现J.如果您更改声明,它可以正常工作:

public struct S<T> : J {...}
Run Code Online (Sandbox Code Playgroud)

在类的情况下,有可能为一个子类要声明一个类的确实实现J.但结构不能扩展,所以如果S没有实现,J那么你可以保证没有"是"的类也S将实现J.因此,J永远不会是一个S<T>.

那么为什么不调用你的显式强制转换运算符呢?我认为答案是在C#规范中,如本SO帖子所述.


6.4.1允许的用户定义转换

C#仅允许声明某些用户定义的转换.特别是,无法重新定义已存在的隐式或显式转换.对于给定的源类型S和目标类型T,如果S或T是可空类型,则让S0和T0引用它们的基础类型,否则S0和T0分别等于S和T. 仅当满足以下所有条件时,才允许类或结构声明从源类型S到目标类型T的转换:

  • S0和T0是不同的类型.
  • S0或T0是发生运算符声明的类或结构类型.
  • S0和T0都不是接口类型.
  • 排除用户定义的转换,从S到T或从T到S不存在转换.

因此,如果我正确阅读,因为它J是一个接口,它不会被识别为您的显式强制转换运算符的候选者.