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

时间:2012-03-05 23:41:26

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

打印哪些:

fffffffff
ffffffff

这似乎是不受欢迎的行为,因为我希望转换为uint在编译时失败!编译器正在使用ulong显式转换运算符,然后以某种方式隐式地将该结果转换为uint而不进行边界检查。这是C#中的错误,如果不是,为什么?

3 个答案:

答案 0 :(得分:13)

  

这是C#中的错误吗?

没有

  

为什么不呢?

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

  

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

不幸的是,你不能总是得到你想要的东西。

  

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

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

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

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

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

答案 1 :(得分:2)

uintulong之间存在显式转换。您允许转换为ulong,并且您明确地转换为uint。你能指望什么?你告诉编译器“别担心,我知道我在做什么”。

  

然后以某种方式隐式地将该结果转换为uint

没有什么隐含的。你正在表演。这对我来说似乎是过于防守的编程。

答案 2 :(得分:1)

在强制转换期间发生溢出,但溢出检查是在C#中“选择加入”。 将演员包裹在:

checked 
{
  ..
}

所以它真的是“按设计”而不是错误。在我认为编译时,返回ulong总是可以转换的。