4

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

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 是一个类,则转换将起作用。

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

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

4

1 回答 1

6

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

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

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

那么为什么它不调用你的显式转换运算符呢?我认为答案在 C# 规范中,如此 SO post中所述。


6.4.1 允许的用户定义转换

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

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

因此,如果我没看错,因为J它是一个接口,它不会被识别为显式转换运算符的候选对象。

于 2012-10-05T19:09:37.543 回答