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

时间:2012-10-05 19:07:31

标签: 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>'
    }
}

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

有一个similar question about converting to a class,答案是派生类可能会实现接口并对是否应该使用用户定义的强制转换产生歧义。但是对于结构体,可能没有派生类型,编译器知道我的结构体没有实现J。

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

1 个答案:

答案 0 :(得分:6)

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

public struct S<T> : J {...}

对于类,可以声明一个类的子类型, 实现J。但是结构不能被扩展,所以如果S没有实现J,那么你可以保证“任何”S的类都不会实现J。因此,J永远不会是S<T>

那为什么不调用你的显式强制转换操作符呢?我认为答案在C#规范中,如this SO post中所述。


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是一个接口,它不会被识别为显式强制转换运算符的候选者。