ChrisM
ChrisM

Reputation: 1168

Why can constants be implicitly converted while static readonly fields cannot?

Given the below code, I wonder why referenceValue = ConstantInt; is valid while referenceValue = StaticInt; fails to compile.

namespace Demo
{
    public class Class1
    {
        private const int ConstantInt = 42;
        private static readonly int StaticInt = 42;

        public void DemoMethod(ref uint referenceValue)
        {
            referenceValue = ConstantInt; // This compiles
            referenceValue = StaticInt; // This claims that the source type 'int' cannot be converted to 'unit' implicitly. 
        }
    }
}

Upvotes: 22

Views: 1857

Answers (3)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249686

Constants are replaced at compile time with their respective value. So from the compiler perspective this referenceValue = ConstantInt; is the same as this referenceValue = 42.

While readonly fields feel similar, they are not. Their value is not truly known at compile time. They are backed by a static field on the class. Their value can be computed, even modified from a static constructor, so the compiler can't check that the value is within the range of uint at compile time.

For example:

public class Class1
{
    private const int ConstantInt = 42;
    private static readonly int StaticInt = 42;

    static Class1()
    {
        StaticInt = -20;
    }

    public void DemoMethod(ref uint referenceValue)
    {
        referenceValue = StaticInt; // it's -20
    }
}

Edit

As pointed out in the comments not all assignments from constants to variables work, long constant to int variable does not work without an explicit cast. This behavior is the same based on the type of the constant, regardless of whether it is a named constant or an inline constant:

private const long ConstantInt = 42;
// Both of these will cause an error:
referenceValue = ConstantInt; // can't be converted implicitly
referenceValue = 42L; // but neither can an inline long constant (the L makes it long)

Upvotes: 20

Ali Faris
Ali Faris

Reputation: 18602

from the doc

The readonly keyword is different from the const keyword. A const field can only be initialized at the declaration of the field. A readonly field can be initialized either at the declaration or in a constructor. Therefore, readonly fields can have different values depending on the constructor used. Also, while a const field is a compile-time constant, the readonly field can be used for runtime constants

as in this line: public static readonly uint l1 = (uint)DateTime.Now.Ticks;

Upvotes: 2

Patrick Hofman
Patrick Hofman

Reputation: 156978

Because constant fields are evaluated on compile time, while readonly fields are evaluated on run time. The interpreter in the compiler treats your integers differently than the runtime does.

The compiler recognizes the value and its type and it can do some basic conversion based on that, as it does in this case. Try and see what happens if you set ConstantInt to a negative number. The compiler will error out. The same is true when you change the type to long or float: there is no compiler conversion rule, so it errors out too.

Upvotes: 11

Related Questions