来自微软的“十进制”源代码 - 它会构建吗?

时间:2014-02-01 19:33:22

标签: c# .net

我最近试图回答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源服务器的此文件实际上是十进制的来源,还是已经过修改?我错过了什么吗?

1 个答案:

答案 0 :(得分:19)

mscorlib等有几个方面不能编写,没有一些有趣的黑客。特别是,存在一些循环依赖性。这是另一种情况,但我认为就C#编译器而言MaxValueMinValueconst是合理的。

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

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

这些字段已经应用了DecimalConstantAttribute,这实际上是解决C#和CLR之间阻抗不匹配的问题:您不能在{C}和CLR中使用decimal类型的常量字段CLR与使用intstring类型的常量字段的方式相同,使用static literal ...进行IL声明。

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

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

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

现在,就您所指的特定C#代码而言,我怀疑有两种可能性:

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

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