c# - constant - static readonly vs static

Static readonly vs const (10)

I've read around about const and static readonly fields. We have some classes which contains only constant values. Used for various things around in our system. So I am wondering if my observation is correct:

Should these kind of constant values always be static readonly for everything that is public? And only use const for internal/protected/private values?

What do you recommend? Should I maybe even not use static readonly fields, but rather use properties maybe?

Const: Const is nothing but "constant", a variable of which the value is constant but at compile time. And it's mandatory to assign a value to it. By default a const is static and we cannot change the value of a const variable throughout the entire program.

Static ReadOnly: A Static Readonly type variable's value can be assigned at runtime or assigned at compile time and changed at runtime. But this variable's value can only be changed in the static constructor. And cannot be changed further. It can change only once at runtime

Reference: c-sharpcorner

const and readonly are similar, but they are not exactly the same.

A const field is a compile-time constant, meaning that that value can be computed at compile-time. A readonly field enables additional scenarios in which some code must be run during construction of the type. After construction, a readonly field cannot be changed.

For instance, const members can be used to define members like:

struct Test
    public const double Pi = 3.14;
    public const int Zero = 0;

Since values like 3.14 and 0 are compile-time constants. However, consider the case where you define a type and want to provide some pre-fab instances of it. E.g., you might want to define a Color class and provide "constants" for common colors like Black, White, etc. It isn't possible to do this with const members, as the right hand sides are not compile-time constants. One could do this with regular static members:

public class Color
    public static Color Black = new Color(0, 0, 0);
    public static Color White = new Color(255, 255, 255);
    public static Color Red   = new Color(255, 0, 0);
    public static Color Green = new Color(0, 255, 0);
    public static Color Blue  = new Color(0, 0, 255);
    private byte red, green, blue;

    public Color(byte r, byte g, byte b) => (red, green, blue) = (r, g, b);

But then there is nothing to keep a client of Color from mucking with it, perhaps by swapping the Black and White values. Needless to say, this would cause consternation for other clients of the Color class. The "readonly" feature addresses this scenario.

By simply introducing the readonly keyword in the declarations, we preserve the flexible initialization while preventing client code from mucking around.

public class Color
    public static readonly Color Black = new Color(0, 0, 0);
    public static readonly Color White = new Color(255, 255, 255);
    public static readonly Color Red   = new Color(255, 0, 0);
    public static readonly Color Green = new Color(0, 255, 0);
    public static readonly Color Blue  = new Color(0, 0, 255);
    private byte red, green, blue;

    public Color(byte r, byte g, byte b) => (red, green, blue) = (r, g, b);

It is interesting to note that const members are always static, whereas a readonly member can be either static or not, just like a regular field.

It is possible to use a single keyword for these two purposes, but this leads to either versioning problems or performance problems. Assume for a moment that we used a single keyword for this (const) and a developer wrote:

public class A
    public static const C = 0;

and a different developer wrote code that relied on A:

public class B
    static void Main() => Console.WriteLine(A.C);

Now, can the code that is generated rely on the fact that A.C is a compile-time constant? I.e., can the use of A.C simply be replaced by the value 0? If you say "yes" to this, then that means that the developer of A cannot change the way that A.C is initialized -- this ties the hands of the developer of A without permission.

If you say "no" to this question then an important optimization is missed. Perhaps the author of A is positive that A.C will always be zero. The use of both const and readonly allows the developer of A to specify the intent. This makes for better versioning behavior and also better performance.

Const : const variable values have to define along with declaration and after that it won't change.const are implicitly static so without creating class instance we can access them. this has a value at compile time

ReadOnly: readonly variable values we can define while declaring as well as using the constructor at runtime. readonly variables cant access without class instance.

Static readonly: static readonly variable values we can define while declaring as well as only through static constructor but not with any other constructor.these variables also we can access without creating class instance(As static variables).

static readonly will be better choice if we have to consume the variables in different assemblies.Please check the full details in below link


Static Read Only : Value can be changed through static constructor at runtime. But not through member Function.

Constant : By default static. Value cannot be changed from anywhere (Ctor, Function, runtime etc no-where).

Read Only : Value can be changed through constructor at runtime. But not through member Function.

You can have a look at my repo : C# property types.

Constants are like the name implies, fields which don't change and are usually defined statically at compile time in the code.

Read only variables are fields that can change under specific conditions.

They can be either initialized when you first declare them like a constant, but usually they are initialized during object construction inside the constructor.

They cannot be changed after the initialization took place, in the conditions mentioned above.

Static read-only sounds like a poor choice to me since, if it's static and it never changes, so just use it public const, if it can change then it's not a constant and then, depending on your needs, you can either use read-only or just a regular variable.

Also, another important distinction is that a constant belongs to the class, while the read-only variable belongs to the instance!

I would use static readonly if the Consumer is in a different assembly. Having the const and the Consumer in two different assemblies is a nice way to shoot yourself in the foot.

One thing to note is const is restricted to primitive/value types (the exception being strings)

Some other things

const int a

  • must be initialized
  • initialization must be at compile time

readonly int a

  • can use default value, without initializing
  • initialization can be at run time

There is a minor difference between const and static readonly fields in C#.Net

const must be initialized with value at compile time.

const is by default static and needs to be initialized with constant value, which can not be modified later on. It can not be used with all datatypes. For ex- DateTime. It can not be used with DateTime datatype.

public const DateTime dt = DateTime.Today;  //throws compilation error
public const string Name = string.Empty;    //throws compilation error
public static readonly string Name = string.Empty; //No error, legal

readonly can be declared as static, but not necessary. No need to initialize at the time of declaration. Its value can be assigned or changed using constructor once. So there is a possibility to change value of readonly field once (does not matter, if it is static or not), which is not possible with const.

This is just a supplement to the other answers. I will not repeat them (now four years later).

There are situations where a const and a non-const have different semantics. For example:

const int y = 42;

static void Main()
  short x = 42;

prints out True, whereas:

static readonly int y = 42;

static void Main()
  short x = 42;

writes False.

The reason is that the method x.Equals has two overloads, one that takes in a short (System.Int16) and one that takes an object (System.Object). Now the question is whether one or both apply with my y argument.

When y is a compile-time constant (literal), the const case, it becomes important that there does exist an implicit conversion from int to short provided that the int is a constant, and provided that the C# compiler verifies that its value is within the range of a short (which 42 is). See Implicit constant expression conversions in the C# Language Specification. So both overloads have to be considered. The overload Equals(short) is preferred (any short is an object, but not all object are short). So y is converted to short, and that overload is used. Then Equals compares two short of identical value, and that gives true.

When y is not a constant, no implicit conversion from int to short exists. That's because in general an int may be too huge to fit into a short. (An explicit conversion does exist, but I didn't say Equals((short)y), so that's not relevant.) We see that only one overload applies, the Equals(object) one. So y is boxed to object. Then Equals is going to compare a System.Int16 to a System.Int32, and since the run-time types do not even agree, that will yield false.

We conclude that in some (rare) cases, changing a const type member to a static readonly field (or the other way, when that is possible) can change the behavior of the program.