我最近试图回答a question that a user posted关于为什么decimal
结构不像其他所有数字原语一样将其最小/最大值声明为const
;相反,Microsoft文档声明它是static readonly.
在研究中,我挖掘了微软的源代码,并提出了一个有趣的发现;源代码(.NET 4.5)使它看起来像const
,与文档明确指出的内容相反(源代码和相关的结构构造函数粘贴在下面)。
public const Decimal MinValue = new Decimal(-1, -1, -1, true, (byte) 0);
public const Decimal MaxValue = new Decimal(-1, -1, -1, false, (byte) 0);
public Decimal(int lo, int mid, int hi, bool isNegative, byte scale)
{
if ((int) scale > 28)
throw new ArgumentOutOfRangeException("scale", Environment.GetResourceString("ArgumentOutOfRange_DecimalScale"));
this.lo = lo;
this.mid = mid;
this.hi = hi;
this.flags = (int) scale << 16;
if (!isNegative)
return;
this.flags |= int.MinValue;
}
这里的线程继续解开,因为我无法看到这将如何根据C#规则合法编译 - 因为虽然它仍然是技术上一个常量,但编译器认为它不是并会给你一个错误The expression being assigned to ... must be constant
。因此,我认为文档称之为static readonly
的原因。
现在,这引出了一个问题:来自Microsoft源服务器的此文件实际上是十进制的来源,还是已经过修改?我错过了什么吗?
答案 0 :(得分:19)
mscorlib等有几个方面不能编写,没有一些有趣的黑客。特别是,存在一些循环依赖性。这是另一种情况,但我认为就C#编译器而言MaxValue
和MinValue
为const
是合理的。
特别是,在其他const
计算中使用它们是有效的:
const decimal Sum = decimal.MaxValue + decimal.MinValue;
这些字段已经应用了DecimalConstantAttribute
,这实际上是解决C#和CLR之间阻抗不匹配的问题:您不能在{C}和CLR中使用decimal
类型的常量字段CLR与使用int
或string
类型的常量字段的方式相同,使用static literal ...
进行IL声明。
(这也是你不能在属性构造函数中使用decimal
值的原因 - 那里,“const-ness”要求是真正的IL级constness。)
相反,C#代码中的任何const decimal
声明都会编译到static initonly
字段,并在其中应用DecimalConstantAttribute
来指定相应的数据。 C#编译器使用该信息将这样的字段视为其他地方的常量表达式。
基本上,CLR中的decimal
不是int
,float
等方式的“已知原始”类型。没有decimal
特定的IL指令。
现在,就您所指的特定C#代码而言,我怀疑有两种可能性:
DecimalConstantAttribute
在很大程度上你可以忽略这一点 - 它不会影响你。遗憾的是MSDN将字段记录为static readonly
而不是const
,因为这给人的错误印象是人们无法在const
表达式中使用它们:(