当没有这样的运算符时显式转换为uint

Zac*_*ach 3 c#

ulong用一个私有数据成员编写了一个简单的包装器.我希望能够将包装器转换ulong为检索数据.我希望强制转换uint和丢失数据是非法的,所以我没有写一个显式的强制转换uint.当C#允许我uint毫无怨言地投射并且即使高位丢失也没有抛出异常时,你可以想象我的惊喜.

这是我的测试代码:

class Program {
    static void Main(string[] args) {
        ULongWrapper a = new ULongWrapper(0xfffffffffUL);
        ulong b = (ulong)a;
        uint c = (uint)a;
        Console.WriteLine("{0:x}", b);
        Console.WriteLine("{0:x}", c);
    }
}
class ULongWrapper {
    private ulong data;
    public ULongWrapper(ulong data) {
        this.data = data;
    }
    public static explicit operator ulong(ULongWrapper x) {
        return x.data;
    }
}
Run Code Online (Sandbox Code Playgroud)

哪个印刷品:

fffffffff
ffffffff
Run Code Online (Sandbox Code Playgroud)

这似乎是不需要的行为,因为我希望强制转换uint在编译时失败!编译器使用ulong显式转换运算符,然后以某种方式隐式地将该结果转换为uint无边界检查.这是C#中的错误,如果没有,为什么?

Eri*_*ert 13

这是C#中的错误吗?

没有.

为什么不?

因为此处演示的行为与规范一致.仔细阅读规范的6.4.4和6.4.5节.(请注意,C#编译器有许多方法与规范的这一部分不一致;实现在不明确的极端情况下有许多错误,特别是涉及提升的运算符.)

我希望转换为uint并丢失数据是非法的.

不幸的是,你无法总是得到你想要的东西.

当C#允许我毫无怨言地投射到uint并且即使高位丢失也没有抛出异常时,你可以想象我的惊讶.

我同意,这有点令人惊讶.

规则是:允许每个用户定义的转换在输入输出上都插入标准转换.此外,如果它是显式转换 - 也就是说,您正在进行转换 - 那么插入的标准转换可以是隐式或显式标准转换.(事实上​​,强制转换可能会导致显式标准转换插入到用户定义的隐式转换中!)

在您的情况下,存在从ULongWrapper到ulong的显式用户定义转换,以及从ulong到uint的标准显式转换.因此,将ULongWrapper转换为uint是合法的.

您可能会考虑不首先实现显式转换,因为显然您不喜欢显式转换的语义.只需编写一个返回底层ulong的方法或属性,并完成它.

  • @Zach:好抓.您已经发现了C#中最奇怪的规则之一.规则是:标准*显式*转换必须是*向后*标准*隐式*转换.由于没有*从int到ulong的隐式转换*(因为int可能是负数)而且没有*从ulong到int的隐式转换*(因为范围),从ulong到int的显式转换是*非标准*!我发现这个规则*疯狂*但是它仍然是C#的规则. (8认同)
  • 那为什么我不能做`int d =(int)a`(产生错误CS0030:不能将类型'TestProgram.ULongWrapper'转换为'int')? (2认同)