以下程序无法编译:
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
成为const,那么它将编译:
class Program
{
public const int x = 50;
static void Main(string[] args)
{
Byte[] y = new Byte[3] { x, x, x };
}
}
我很好奇这里发生了什么。如果int
无法隐式地转换为字节,编译器是否会动态创建我的const的“字节”版本,或者它是否编译它就好像我已经进行了显式转换,因为它认为一个字节的常量值“安全”?也许编译器将此解释为我写的:
Byte[] y = new Byte[3] { 50, 50, 50 };
由于这是合法的,我对编译器在这里所做的事情更感兴趣。
答案 0 :(得分:6)
我推荐你参考C#4规范的第6.1.9节,其中规定:
如果常量表达式的值在目标类型的范围内,则int类型的常量表达式可以转换为sbyte,byte,short,ushort,uint或ulong类型。
你的问题是:
编译器是否会动态创建我的const的“字节”版本,或者它是否编译它就好像我已经进行了显式转换,因为它认为一个字节的常量值“安全”?
我不明白这两件事之间的区别;对我来说,它们听起来是一回事。
答案 1 :(得分:5)
编译器只会将常量视为在那里编写数字,但需要进行隐式转换。
在您的第三个代码段中,这三个50
都是System.Int32
。将鼠标悬停在其上并阅读Visual Studio中的工具提示。为什么编译器错误不在这里?因为编译器在编译时知道该值并且知道它将适合byte
。
答案 2 :(得分:2)
对于字节,非常量值可能太大,而常量值是常量,并且在这种情况下保证低于阈值。
答案 3 :(得分:1)
常量在编译时被“烘焙”。
如何编译常量的一个值得注意的结果是,如果针对程序集进行编译,它将在编译时使用常量值。如果稍后在运行时绑定不同版本的程序集,它将使用原始常量,即使它们在新版本的程序集中已更改。这也适用于Enum常量。故事的寓意是(公共)常数值确实应该是恒定的;如果有可能发生有意义的更改,请改用静态只读字段。
答案 4 :(得分:0)
基本上它归结为不同之处在于,当编译器在编译时知道该值时,则允许强制转换是较大数字类型的值在较小数字类型的允许范围内。如果编译器不知道是否是这种情况,那么除非你使用显式转换来确保程序运行时它将在该范围内,否则不允许这样做。
尽管我们知道x的值在声明和使用之间不太可能发生变化,但是肯定知道它不会改变需要编译器不会尝试的复杂分析(并且实际上不可能总是这样做)得到正确的)。如果变量不是const,则编译器不会对其实际值进行推断。
答案 5 :(得分:0)
答案是:因为const由预处理程序例程变为文字,并且被解释为“代码”,而变量则不是。