为什么const int隐式转换为字节,而变量int不隐式转换

本文关键字:转换 int 变量 字节 const 为什么 | 更新日期: 2023-09-27 18:21:39

以下程序不会编译:

   class Program
   {
      static void Main(string[] args)
      {
         int x = 50;
         Byte[] y = new Byte[3] { x, x, x };
      }
   }

毫不奇怪,我会得到错误Cannot implicitly convert type 'int' to 'byte'

然而,如果我将x设为常量,那么它将编译:

   class Program
   {
      public const int x = 50;
      static void Main(string[] args)
      {
         Byte[] y = new Byte[3] { x, x, x };
      }
   }

我很好奇这里发生了什么事。如果int不能隐式转换为字节,编译器是动态创建我的常量的"字节"版本,还是像我进行了显式转换一样编译它,因为它认为常量值对字节来说是"安全的"?也许编译器将其解释为我写过:

Byte[] y = new Byte[3] { 50, 50, 50 };

由于这是合法的,我更好奇编译器在这里做什么。

为什么const int隐式转换为字节,而变量int不隐式转换

请参阅C#4规范的6.1.9节,其中指出:

int类型的常量表达式可以转换为sbyte、byte、short、ushort、uint或ulong类型,前提是常量表达式的值在目标类型的范围内。

你的问题是:

编译器是动态创建我的const的"字节"版本,还是像我放入了显式强制转换一样编译它,因为它认为常量值对字节来说是"安全的"?

我不明白这两件事之间的区别;它们对我来说听起来是一样的。

编译器只会将常量视为在其中写入数字,但需要进行隐式转换。

在您的第三个片段中,这三个50都是System.Int32。将鼠标悬停在它上面,然后阅读Visual Studio中的工具提示。为什么这里没有编译器错误?因为编译器在编译时知道该值,并且知道它将适合byte

非常数值对于Byte来说可能太大,而常数值是恒定的,在这种情况下保证低于阈值。

常量在编译时"烘焙"。

如何编译常量的一个值得注意的结果是,如果根据程序集进行编译,它将在编译时使用常数值。如果以后在运行时绑定到程序集的其他版本,它将使用原始常量,即使它们在程序集的新版本中发生了更改。这也特别适用于枚举常量。这个故事的寓意是,(公众)不变的价值观真的应该是不变的;如果有任何可能发生有意义的更改,请改用静态只读字段。

基本上,它的区别在于,当编译器在编译时知道值时,如果较大数字类型的值在较小数字类型的允许范围内,则允许强制转换。如果编译器不知道是否是这种情况,那么它是不允许的,除非您使用显式强制转换来确保它在程序运行时处于该范围内。

尽管我们知道x的值在声明和使用之间不太可能发生变化,但要确定它不会发生变化,需要进行编译器没有尝试的复杂分析(实际上不可能总是正确的)。如果一个变量不是const,那么编译器不会对其实际值进行推断。

答案是:因为const通过预处理器例程变成了一个文本,并被解释为"代码",而变量则没有。