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?
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:
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 :(
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With