8

In C#, MinValue field is defined for numeric types with:

static readonly modifiers for decimal type (Link to MSDN Libray for .NET 4.5):

public static readonly decimal MinValue

const modifier for all other numeric types:

//Integral signed numeric types
public const sbyte MinValue
public const short MinValue
public const int MinValue
public const long MinValue

//Integral unsigned numeric types
public const byte MinValue
public const ushort MinValue
public const uint MinValue
public const ulong MinValue

//Real numeric types
public const float MinValue
public const double MinValue

Why const modifier is not used to define Decimal.MinValue field ?

Remarks:

① Same question applies to numeric types MaxValue field.

② VB, C++ and F# also use different modifiers for decimal type so this question is not specific to C# language.

Fabien Launay
  • 639
  • 7
  • 16
  • 1
    `Decimal` is not as primitive as the other types. – Mark Hurd Feb 01 '14 at 18:45
  • 2
    Note that (no matter what tricks were needed to make that possible in the source code), the `MinValue` field of the `Decimal` struct **is** a `const`, and acts like one. If you use Visual Studio and use "Go To Definition" (F12) on `decimal`, you will see "metadata" (C# code generated from the actual assembly via reflection) that shows `[DecimalConstant(0, 128, 4294967295, 4294967295, 4294967295)] public const decimal MinValue = -79228162514264337593543950335m;`. So `MinValue` acts as a const. You can declare other `const` values from it, use it as default value for optional parameters, etc. – Jeppe Stig Nielsen Feb 01 '14 at 20:10
  • @MarkHurd While that is correct in .NET, it is important here that in the C# Specification, the type `decimal` is a **predefined type** in the language, it is a so-called simple type in C#, see [4.1 Value types](http://msdn.microsoft.com/en-us/library/aa691140.aspx) and [4.1.4 Simple types](http://msdn.microsoft.com/en-us/library/aa691144.aspx) (here I link an old version of the spec, but it is the same in the newest version). And C# allows `const` fields for all these "simple types", including `decimal`. Now when mscorlib contains source code of a "predefined type", some tricks may be needed. – Jeppe Stig Nielsen Feb 01 '14 at 20:36
  • 1
    So really, the question is no longer relevant, as in the actual code it is a `const` and not a `static readonly` as the documentation states. But, the rabbit hole is still pretty deep. – theMayer Feb 03 '14 at 04:23

4 Answers4

2

This is an interesting question. I did some research, and the MS documentation on Decimal Min/Max fields explicitly says (note the wording is the same for both; shown in brackets for clarity):

The value of this constant is [negative] 79,228,162,514,264,337,593,543,950,335.

The following code compiles with no problem:

public const decimal MaxValue = 79228162514264337593543950335M;

- Edit -

Note: here is the assignment of the field from the source for .NET 4.5 (downloaded PDB source from MS), the decimal constructor that is called by this code. Note that it is declaring a const value. It appears, at least for 4.5, that the documentation is wrong. (This would not be the first time MS documentation is incorrect). It also appears that the source code won't compile, as pointed out in a comment by @Daniel.

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

Also note: in the 2.0 framework, decimal is declared outright:

public const Decimal MaxValue = 79228162514264337593543950335m;

So, inconsistency and incorrect documentation is the conclusion I have reached. I will leave it to others to look at the other framework versions for a pattern.

theMayer
  • 15,456
  • 7
  • 58
  • 90
  • Why there is const instead readonly, is it problem of decompiler? This code will not compiled with const keyword – Daniil Grankin Feb 01 '14 at 19:08
  • Good point - this must be version-specific. 2.0 framework explicitly says `public const Decimal MaxValue = 79228162514264337593543950335m;` – theMayer Feb 01 '14 at 19:13
  • It's impossible to use this in code in .net `public const Decimal MaxValue = new Decimal(-1, -1, -1, false, (byte) 0);` Because constant initializer must be compile-time constant but not invocation of constructor. Is it clear? – Daniil Grankin Feb 01 '14 at 19:13
  • Try to compile similar code, it doesn't matter struct or class in this case. – Daniil Grankin Feb 01 '14 at 19:18
  • Maybe the MS source is incorrect? This wasn't a decompilation, it was downloaded from MS source server. – theMayer Feb 01 '14 at 19:21
  • 1
    Oh, I don't know. It's strange with strange comment `This field is constant and read-only.` for MinValue and MaxValue. I've thought it's different things:) – Daniil Grankin Feb 01 '14 at 19:24
  • I think the source was doctored. Wonder how many other doctored source files there are? – theMayer Feb 01 '14 at 19:36
1

Firstly, note that these Decimal values are seen as constants from the languages' point of view (but not the CLR), as Jon Skeet mentions in his answer to rmayer06's related question.

(I thought the reason for using ReadOnly instead of Const was so that the constructor was not called on every use of a Const, except that is :-( )

If you compile: x == Decimal.MaxValue in C# or VB.NET, the constant is constructed as if it was really a Const.

In VB.NET this is not true for Decimal.One, Decimal.Zero or Decimal.MinusOne, but these are treated as constants in C#. (BTW String.Empty is not seen as a constant in either language.)

So I believe these are baked into to languages as constants (sometimes, in VB's case).

In VB's case it does seem to prefer to load the ReadOnly values, except for MaxValue, and Minvalue. (That is Const y1 As Decimal = Decimal.One is effectively aliased by VB, but truly treated as a constant in C#.)

BTW Date.MaxValue is also ReadOnly, but it is not seen as a constant by VB.NET (even though it does have Date literals).

UPDATE: I haven't checked what the current results are for the most recent VB.NET or C# but the reference source does not treat any of Decimal.One, Decimal.Zero, Decimal.MinusOne, Decimal.MaxValue or Decimal.MinValue specially; they're all just public const.

Community
  • 1
  • 1
Mark Hurd
  • 10,665
  • 10
  • 68
  • 101
1

Although MSDN library describes decimal MinValue field as being static readonly, C# compiler treats it as const.

If MinValue field was readonly, following code would not compile, but it actually does compile.

const decimal test = decimal.MinValue - decimal.MinValue;

Remarks:

① Same answer applies to decimal type MaxValue field.

② For further details, Jon Skeet's gives here an insight on how constant field implementation at IL level differs between:

  • Primitive numeric types (integrals, float and double) and
  • The non primitive numeric decimal type.
Community
  • 1
  • 1
Fabien Launay
  • 639
  • 7
  • 16
0

I'd have thought it was for readability of the source code

public const Decimal MaxValue = new Decimal(-1, -1, -1, false, (byte) 0);

seems more readable than the magic number:

public const Decimal MaxValue = 79228162514264337593543950335m
Joe
  • 122,218
  • 32
  • 205
  • 338
  • I don't know about more readable, but certainly it is more clear on where the number materialized from. – theMayer Feb 03 '14 at 04:20