来自微软的“Decimal”源代码-它能构建吗?

11
我最近尝试回答用户发布的一个问题,关于为什么decimal结构体不像其他数字原始类型一样声明其Min/Max值为const; 相反,Microsoft文档指出它是static readonly. 在研究中,我查看了Microsoft源代码,并发现了一个有趣的发现; 源代码(.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源服务器,实际上是decimal的源代码,还是经过篡改?我有什么遗漏吗?


2
我并不确定具体细节,但我知道核心的 .Net 库是通过一种非标准的方式进行编译的。其中一个例子是跨程序集允许循环引用(程序集 1 引用了程序集 2 中的某个类型,而程序集 2 又引用了程序集 1 中的某个类型)。这使我相信用于核心库的编译器并不是公开发布的标准编译器。尽管如此,我仍然找不到讨论这个话题的文章。 - Basic
1个回答

22

mscorlib和类似的一些方面如果没有一些有趣的技巧,就无法按原样编译。特别是存在一些循环依赖关系。这是另一种情况,但我认为就C#编译器而言,将MaxValueMinValue视为const是合理的。

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

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

这些字段应用了 DecimalConstantAttribute,这实际上是一种解决 C# 和 CLR 之间阻抗不匹配的方法:你无法像使用类型为intstring的常量字段一样在CLR中拥有类型为decimal的常量字段,并使用static literal ... 进行IL声明。

(这也是为什么您无法在属性构造函数中使用decimal值的原因 - 在那里,“const-ness”要求是真正的IL级别的常量性。)

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

基本上,decimal在CLR中不是“已知的基元”类型,就像intfloat等那样。没有decimal-特定的IL指令。

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

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

在很大程度上,您可以忽略它-它不会影响您。不过,遗憾的是,MSDN将这些字段记录为static readonly而不是const,这会给人们带来错误的印象,认为不能在const表达式中使用它们 :(


这肯定符合我所想的方向,但你显然对.NET的“内核”了解更多。我听说十进制数比较不原始,但是它有什么特别之处呢?是由于实现造成的吗? - theMayer
2
@rmayer06:就CLR而言,它不是原始类型 - 例如,typeof(decimal).IsPrimitive返回false。据我所知,CLR对于decimal没有任何特殊的了解。 - Jon Skeet
"MSDN文档将字段描述为“static readonly”,这真是遗憾": 很多文档都基于实际声明,可以通过Reflector或其他反编译工具查看。就像在对象浏览器中有时无法看到String被视为sealed一样,我认为这只是另一个怪癖。 - Mark Hurd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接