---
title: "Is public const bad?"
description: "Is declaring a number or string as `public const` considered bad practice? Let's have a look what a `const` variable means in the first place.\nLet's find out and also check what are the alternatives."
updated: 2022-04-21
tags: ["C#", "Const"]
canonical: "https://steven-giesel.com/blogPost/bfb3e48e-c18b-40f1-97f8-b4c8d97a0f95/is-public-const-bad"
---

# Is public const bad?

Is declaring a number or string as `public const` considered bad practice? Let's have a look what a `const` variable means in the first place.

Let's take the definition from the official [C# Reference](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/const):

> You use the `const` keyword to declare a constant field or a constant local. Constant fields and locals aren't variables and may not be modified. Constants can be numbers, Boolean values, strings, or a null reference. Don’t create a constant to represent information that you expect to change at any time.

Now for startes this part is important "*Constant fields and locals aren't variables...*". That is essential. Let's have a look at the following code snippet:
```csharp
using System;

Console.Write(MyClass.MyConstantString);

public class MyClass 
{
    public const string MyConstantString = "Hello";
}
```

The compiler will lower that term to the following code <sup>[Source on sharplab.io](https://sharplab.io/#v2:EYLgtghglgdgPgAQEwEYCwAoTBhA9jAZ1wBsBTAOgHUAnKAF1IAoBZAT22IgIPLb0LoQYdAMp1aMAOYBKANyZMCAMwACZCr6duKgN6YVBtaoDG+AnTUoADBvZnBwsRMkqAvCoBEACVLFiuD3kMAF8gA=)</sup>
```csharp
internal class Program
{
    private static void <Main>$(string[] args)
    {
        Console.Write("Hello");
    }
}
public class MyClass
{
    public const string MyConstantString = "Hello";
}
```

Hupps. Where is the reference to `MyClass.MyConstantString` in the `Console.Write`? Exactly not existing anymore. `const` fields and locals are indeed no variables and therefore will be "replaced" by the compiler at compile-time everywhere the constant is used.
That can bring a big problem:

## Referencing assemblies
Just imagine you have the following class in Assembly A:
```csharp
public class MyClassInAssemblyA
{
    public const string MyConstantString = "Hello";
}
```

And an user of the class in Assembly B:
```csharp
public class MyClassInAssemblyA
{
    public void WriteSomething() => Console.WriteLine(MyClassInAssemblyA.MyConstantString);
}
```

If we compile this and call `WriteSomething` the console will print "Hello". Now we go further and change `MyConstantString` from "Hello" to "World". We redeploy Assembly A but **not** Assembly B, what will be the output of `WriteSomething`? Still "Hello". Why? Because as shown earlier the `const` string gets hardcoded into the assembly. That means to reflect the latest changes you also have to recompile Assembly B. Now that is not a big use when you develop software where everything is under your control, but it can get tricky for example if you develop plugins, where the caller does not automatically get recompiled.

## How to fix that
The easiest fix is to use a `readonly static` field. So taken our example from the beginning, we refactor this to a `readonly static` field:
```csharp
using System;

Console.Write(MyClass.MyConstantString);

public class MyClass 
{
    public static readonly string MyConstantString = "Hello";
}
```

And the resulting code will look like [this](https://sharplab.io/#v2:EYLgtghglgdgPgAQEwEYCwAoTBhA9jAZ1wBsBTAOgHUAnKAF1IAoBZAT22IgIPLb0LoQYdAMp1aMAOYBKANyZMCAMwACZCr6duKgN6YVBtaoQoAbCuqkIAE3zFWalAAYN7fAUHCxEySoC8KgBEABKkxMS4gfIYAL5AA=):
```csharp
internal class Program
{
    private static void <Main>$(string[] args)
    {
        Console.Write(MyClass.MyConstantString);
    }
}
public class MyClass
{
    public static readonly string MyConstantString = "Hello";
}
```

We can clearly see that the `Console.Write` now takes the "real" reference rather than the hardcoded string. Meaning if we change `MyClass.MyConstantString` it gets automatically reflected there as well.

:warning: Changing from `public const` to `public static readonly` is considered a breaking change. You lose binary, source, and reflection compatibility. So if you do semantic versioning you'd have to increase the major number. Be aware of that.

Also you can't use `static readonly` fields/variables in the following scenarios:
 * Attribute arguments
 * Switch statements
 * Optional parameter declarations

## Is `public const` bad then?
As always: **It depends**. Mainly on the fact if you have full control over the whole flow and source code, if you have most likely not. Also if you are 100% certain that your `const` will never change, go for it. Something like `public const int Zero = 0` or Pi. Otherwise be very cautious if you want to use `public const`. The same applies for `protected const`. Everything which is visible **outside** your assembly.

Of course `private const` or `internal const` are safe in this regard.