当没有这样的运算符时,显式强制转换为uint
本文关键字:转换 uint 运算符 | 更新日期: 2023-09-27 18:26:42
我已经用一个私有数据成员编写了一个简单的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#中的一个错误吗?如果不是,为什么?
这是C#中的一个错误吗?
没有。
为什么不呢?
因为这里展示的行为与规范一致。仔细阅读本规范第6.4.4节和第6.4.5节。(请注意,C#编译器在许多方面与规范的这一部分不一致;该实现在模糊的角落情况下有许多错误,特别是涉及提升运算符。)
我希望强制转换为uint并丢失数据是非法的。
不幸的是,你不可能总是得到你想要的。
你可以想象,当C#允许我毫无怨言地抛出uint,并且即使高位丢失也没有抛出异常时,我会感到惊讶。
我同意,这有点令人惊讶。
规则是:每个用户定义的转换都允许在输入和输出上插入标准转换。此外,如果是显式转换,也就是说,您正在执行强制转换,则插入的标准转换可能是隐式或显式标准转换。(事实上,强制转换可能会导致显式标准转换插入到用户定义的隐式转换中!)
在您的案例中,有一个从ULongWrapper到ulong的显式用户定义转换,以及从ulong到uint的标准显式转换。因此,将ULongWrapper强制转换为uint是合法的。
您可能首先考虑不实现显式转换,因为显然您不喜欢显式转换的语义。只需编写一个返回底层ulong的方法或属性,然后使用它即可。
uint
和ulong
之间存在显式转换。您允许转换为ulong
,并显式地强制转换为uint
。你期待什么?你是在告诉编译器"别担心,我知道我在做什么"。
然后以某种方式隐式地将结果转换为uint
这并没有什么隐含的。你在表演演员阵容。对我来说,这似乎是过于防御性的编程。
在强制转换过程中会发生溢出,但溢出检查在C#中是"选择加入"的。包裹铸件:
checked
{
..
}
所以它实际上是"设计出来的",而不是一个bug。我认为,返回一个ulong在编译时总是可以抛出的。