C#
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C#
-
Section 4: Working with Data
-
Section 5: Error Handling
-
Section 6: Delegates and Events
-
Section 7: Async Programming
-
Section 8: More Language Features
-
Section 9: File I/O and Serialization
-
Section 10: Networking in .NET
-
Section 11: The .NET Ecosystem
-
Section 12: Memory and Performance
-
Section 13: Concurrency Beyond Async
-
Section 14: Reflection and Attributes
-
Section 15: Testing and Best Practices
-
Section 16: Design Patterns in C#
-
Section 17: Standard Library Deep Dive
-
Section 18: Data Structures and Algorithms in C#
-
Section 19: GUI and Desktop Development Overview
-
Section 20: Practical Projects
-
Section 21: More Practice Exercises
-
Section 22: More Standard Library and Text Processing
-
Section 23: More Design Patterns
-
Section 24: More Projects
-
Section 25: Interview Practice
-
Section 26: C# Keywords Reference (Modifiers)
-
Section 27: C# Keywords Reference (Statements)
-
Section 28: C# Keywords Reference (Operators)
-
Section 29: BCL: System.Collections.Generic
-
Section 30: BCL: System.Linq
-
Section 31: BCL: System.Threading
-
Section 32: BCL: System.IO
-
Section 33: BCL: System.Text and System.Text.Json
-
Section 34: BCL: System.Net.Http
-
Section 35: C# Language Specification Topics
-
Section 36: More Practice Exercises
-
Section 37: More Async Patterns
-
Section 38: More BCL: System.Reflection and System.Diagnostics
-
Section 39: Nullable Reference Types In Depth
-
Section 40: C# Records and Pattern Matching In Depth
-
Section 41: Dependency Injection Deep Dive
-
Section 42: More Interview and Whiteboard Practice
165: The readonly and const Modifiers Compared
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
PhysicsEngineSettingsobject 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.
There are no comments for now.