使用 Casting null does not compile 作为灵感,来自 Eric Lippert 的评论:
这展示了一个有趣的案例。 “uint x = (int)0;”会 即使 int 不能隐式转换为 uint,也会成功。
我们知道这不起作用,因为
object
无法分配给 string
:
string x = (object)null;
但是确实如此,尽管直观上不应该:
uint x = (int)0;
当 int
不能隐式转换为
uint
时,为什么 编译器允许这种情况?
C# 语言将整数常量转换视为非常特殊;这是规范的第 6.1.9 节:
int 类型的常量表达式可以转换为 sbyte、byte、short、ushort、uint 或 ulong 类型,前提是常量表达式的值在目标类型的范围内。 long 类型的常量表达式可以转换为 ulong 类型,前提是常量表达式的值不为负。
这允许您执行以下操作:
byte x = 64;
否则需要丑陋的显式转换:
byte x = (byte)64; // gross
以下代码将失败,并显示消息“无法将类型‘int’隐式转换为‘uint’。存在显式转换(是否缺少强制转换?)”
int y = 0;
uint x = (int)y;
这将失败:“常量值'-1'无法转换为'uint'”
uint x = (int)-1;
所以
uint x = (int)0;
起作用的唯一原因是因为编译器认为 0 (或任何其他值 > 0)是一个编译时常量,可以转换为 uint
一般来说,编译器有 4 个步骤来转换代码。 文本被标记化 > 标记被解析 > AST 被构建 + 链接 > AST 被转换为目标语言。
对数字和字符串等常量进行求值是第一步,编译器可能会将 0 视为有效标记并忽略强制转换。