来自微软的’Decimal’源代码 – 它会构建吗?

我最近试图回答一个用户发布的问题,为什么decimal结构不像其他每个数字原语一样将其Min / Max值声明为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源服务器的这个文件实际上是十进制的来源,还是已被修改过? 我错过了什么吗?

mscorlib等的一些方面不会像编写那样编译,没有一些有趣的黑客攻击。 特别是,存在一些循环依赖性。 这是另一种情况,但我认为就C#编译器而言,将MaxValueMinValue视为const是合理的。

特别是,在其他const计算中使用它们是有效的:

 const decimal Sum = decimal.MaxValue + decimal.MinValue; 

这些字段应用了DecimalConstantAttribute ,这实际上是解决C#和CLR之间阻抗不匹配的问题:在CLR中不能有一个常量的decimal字段,就像你可以有一个常数一样intstring类型的字段,带有使用static literal ...的IL声明static literal ...

(这也是你不能在属性构造函数中使用decimal值的原因 – 那里,“const-ness”要求是真正的IL级constness。)

相反,C#代码中的任何const decimal声明都被编译为static initonly字段, DecimalConstantAttribute应用了DecimalConstantAttribute来指定相应的数据。 C#编译器使用该信息将这样的字段视为其他地方的常量表达式。

基本上,CLR中的decimal不是intfloat等方式的“已知原始”类型。 没有decimal特定的IL指令。

现在,就你所指的具体C#代码而言,我怀疑有两种可能性:

  • 不,这不是使用的确切源代码。
  • 用于编译mscorlib和框架的其他核心方面的C#编译器可能应用了特殊标志以允许此类代码,将其直接转换为DecimalConstantAttribute

在很大程度上你可以忽略这一点 – 它不会影响你。 遗憾的是,MSDN将字段记录为static readonly而不是const ,因为这给人错误的印象,即不能在const表达式中使用它们:(