我认为这个问题会让我在 Stack Overflow 上一炮而红。
假设您有以下类型:
// represents a decimal number with at most two decimal places after the period
struct NumberFixedPoint2
{
decimal number;
// an integer has no fractional part; can convert to this type
public static implicit operator NumberFixedPoint2(int integer)
{
return new NumberFixedPoint2 { number = integer };
}
// this type is a decimal number; can convert to System.Decimal
public static implicit operator decimal(NumberFixedPoint2 nfp2)
{
return nfp2.number;
}
/* will add more nice members later */
}
它的编写方式是只允许不丢失精度的安全转换。但是,当我尝试此代码时:
static void Main()
{
decimal bad = 2.718281828m;
NumberFixedPoint2 badNfp2 = (NumberFixedPoint2)bad;
Console.WriteLine(badNfp2);
}
我很惊讶它会编译,并且在运行时会写出2
. 从int
(of value 2
) 到的转换NumberFixedPoint2
在这里很重要。(如果有人想知道,最好WriteLine
使用 a的重载。)System.Decimal
为什么在地球上允许从decimal
到转换?NumberFixedPoint2
(顺便说一下,在上面的代码中,如果NumberFixedPoint2
从结构体变为类,则没有任何变化。)
您是否知道 C# 语言规范是否说从int
到自定义类型的隐式转换“暗示”存在从decimal
到该自定义类型的“直接”显式转换?
它变得更糟。试试这个代码:
static void Main()
{
decimal? moreBad = 7.3890560989m;
NumberFixedPoint2? moreBadNfp2 = (NumberFixedPoint2?)moreBad;
Console.WriteLine(moreBadNfp2.Value);
}
如您所见,我们在Nullable<>
这里有(提升)转化率。但是哦,是的,那确实编译。
在x86 “平台”中编译时,此代码会写出一个不可预测的数值。哪一个因时而异。例如,有一次我得到了2289956
. 现在,这是一个严重的错误!
当为x64平台编译时,上面的代码使应用程序崩溃,并显示一条System.InvalidProgramException
消息Common Language Runtime detected an invalid program。根据InvalidProgramException
该类的文档:
通常,这表明生成程序的编译器中存在错误。
有没有人(比如 Eric Lippert,或者在 C# 编译器中使用提升转换的人)知道这些错误的原因?比如,我们在代码中没有遇到它们的充分条件是什么?因为类型NumberFixedPoint2
实际上是我们在真实代码中拥有的东西(管理其他人的钱和东西)。