Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

'Decimal' source code from Microsoft - will it build?

Tags:

c#

.net

I was recently attempting to answer a question that a user posted about why the decimal struct does not declare its Min/Max values as const like every other numeric primitive; rather, the Microsoft documentation states that it is static readonly.

In researching that, I dug through the Microsoft source code, and came up with an interesting discovery; the source (.NET 4.5) makes it look like a const which is in opposition to what the documentation clearly states (source and relevant struct constructor pasted below).

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;
}

The thread here continues to unravel, because I can't see how this would compile legally under the rules of C# - because while it still is technically a constant, the compiler thinks it isn't and will give you an error The expression being assigned to ... must be constant. Hence what I believe is the reason that the docs call it a static readonly.

Now, this begs a question: is this file from the Microsoft source server actually the source for decimal, or has it been doctored? Am I missing something?

like image 259
theMayer Avatar asked Feb 01 '14 19:02

theMayer


1 Answers

There are a few aspects of mscorlib and the like which wouldn't compile as-written, without some interesting hacks. In particular, there are some cyclic dependencies. This is another case, but I think it's reasonable to consider MaxValue and MinValue as being const as far as the C# compiler is concerned.

In particular, it's valid to use them within other const calculations:

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

The fields have the DecimalConstantAttribute applied to them, which is effectively a hack to get around an impedance mismatch between C# and the CLR: you can't have a constant field of type decimal in the CLR in the same way that you can have a constant field of type int or string, with an IL declaration using static literal ....

(This is also why you can't use decimal values in attribute constructors - there, the "const-ness" requirement is true IL-level constness.)

Instead, any const decimal declaration in C# code is compiled to a static initonly field with DecimalConstantAttribute applied to it specifying the appropriate data. The C# compiler uses that information to treat such a field as a constant expression elsewhere.

Basically, decimal in the CLR isn't a "known primitive" type in the way that int, float etc are. There are no decimal-specific IL instructions.

Now, in terms of the specific C# code you're referring to, I suspect there are two possibilities:

  • No, this isn't the exact source code used.
  • The C# compiler used to compile mscorlib and other core aspects of the framework may have special flags applied to allow such code, converting it directly to DecimalConstantAttribute

To a large extent you can ignore this - it won't affect you. It's a shame that MSDN documents the fields as being static readonly rather than const though, as that gives the mistaken impression that one can't use them in const expressions :(

like image 188
Jon Skeet Avatar answered Oct 28 '22 02:10

Jon Skeet