【问题标题】:Why isn't my cast operator from T to SomeStruct<T> working when T is an interface?当 T 是接口时,为什么我的从 T 到 SomeStruct<T> 的转换运算符不起作用?
【发布时间】:2012-09-26 23:34:34
【问题描述】:

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

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。

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

【问题讨论】:

    标签: c# generics interface operator-overloading type-conversion


    【解决方案1】:

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

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

    在类的情况下,可以声明类的子类型确实实现J。但是结构不能被扩展,所以如果S 没有实现J,那么你可以保证没有“是”的类S 将永远实现J。因此,J 永远不会是 S&lt;T&gt;

    那么为什么它不调用您的显式转换运算符?我认为答案在 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 是一个接口,它不会被识别为显式转换运算符的候选对象。

    【讨论】:

    • 我为从 T 到 S 的“任何”类型 T 定义了一个转换运算符。我天真地期望 J 是这样的 T,所以我期望编译器输出调用我的显式转换运算符进行转换的代码。我在问为什么这种期望是错误的。 (不幸的是,C# 在用户定义的转换和语言定义的转换之间存在歧义。)
    猜你喜欢
    • 2018-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-20
    • 1970-01-01
    • 1970-01-01
    • 2011-04-04
    • 1970-01-01
    相关资源
    最近更新 更多