Skip to Content
Course content

165: The readonly and const Modifiers Compared

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I've run into this a dozen times when onboarding new devs: they see a value that shouldn't change and they immediately reach for const. It seems like the logical choice. But there's a nuance to how C# handles memory and compilation that makes readonly a completely different beast. Let's look at this by trying to build a simple configuration class for a game server.

Trying the obvious choice

Let's start with something simple. Every game server has a maximum number of players. That's never going to change while the app is running, so I'll start with a const.

public class GameServer
{
    public const int MaxPlayers = 64;
}

This works perfectly. If I reference GameServer.MaxPlayers anywhere in my code, the compiler literally replaces that variable name with the number 64. It's efficient. But here is where I usually run into trouble. What if I want the max players to be determined by a config file when the server starts up?

Where const hits a wall

I'll try to move that initialization into the constructor so I can pass in a value from a settings file. Let's see what happens:

public class GameServer
{
    public const int MaxPlayers;

    public GameServer(int playersFromConfig)
    {
        MaxPlayers = playersFromConfig; // Error!
    }
}

The compiler just yelled at me. It tells me that a const field must be initialized at the time of declaration. I can't wait until the program is actually running to decide what a const is. That's because const is a compile-time constant. The value is baked directly into the Intermediate Language (IL) code. If it's not there when I hit "Build," the compiler has nothing to bake in.

Bringing in readonly

This is where I switch gears to readonly. I want a value that is "constant" once the object is created, but I want the flexibility to set it during the initialization phase. Let's try that instead:

public class GameServer
{
    public readonly int MaxPlayers;

    public GameServer(int playersFromConfig)
    {
        MaxPlayers = playersFromConfig; // This works!
    }
}

Now we're talking. The compiler is happy. I can now create one server instance with 64 players and another with 128, and both will treat MaxPlayers as an immutable value for the rest of their lives.

The subtle difference

You might be wondering, "If readonly can do everything const can do, why bother with const?" I'll try to break the readonly field in a regular method to show you the limit.

public void UpdatePlayerLimit(int newLimit)
{
    MaxPlayers = newLimit; // Error!
}

Just like const, readonly prevents me from changing the value after the constructor finishes. So, the real difference is when the value is assigned. const happens at compile-time (hardcoded), while readonly happens at runtime (assigned during object creation).

One last pro tip: if you're building a library that other people use, be careful with const. If you change a const value in your library and republish it, the apps using your library won't see the change until they are recompiled. They have the old value baked into their own binaries. readonly avoids this because it's looked up at runtime.




📋 Practical Task

Implementing a PhysicsEngineSettings Class

You are building a physics engine. You need to create a class called PhysicsEngineSettings that handles two types of values:

  • The Speed of Light: This is a universal constant that will never change, regardless of the simulation. Use the most restrictive modifier possible.
  • The Gravity Strength: This depends on which planet the simulation is running on (e.g., Earth vs. Mars). It must be set when the PhysicsEngineSettings object is created via the constructor and cannot be changed afterward.

Requirements:
1. Define a field for SpeedOfLight (double) initialized to 299792458.
2. Define a field for GravityStrength (double) that is assigned via the constructor.
3. Ensure both fields are protected from being modified after the object is initialized.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.