Skip to Content
Course content

164: The static Modifier In Depth

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

You've probably seen the static keyword since the very first line of code you wrote in this course—static void Main—but there is a persistent myth that hangs around as learners move into intermediate C#. A lot of people assume that static means "constant" or "unchangeable." They see a static variable and think it's just a fancy way of doing a const.

That is completely wrong. Let me show you why.

public class GameSettings 
{
    public static int VolumeLevel = 50; 
}

// Later in the code...
GameSettings.VolumeLevel = 80; // This works perfectly.
GameSettings.VolumeLevel++;     // This also works.

If static meant "constant," the compiler would have stopped me the moment I tried to change the volume. But it didn't. The VolumeLevel changed across the entire application. The misconception is confusing mutability (whether a value can change) with scope (who owns the value).

"Static means Constant" vs. "Static means Type-Owned"

When you mark a member as static, you aren't telling C# to lock the value; you're telling it that this member belongs to the Type itself, rather than to a specific instance of that type.

Think of a class as a blueprint for a house. A non-static field, like int numberOfWindows, is a property of the specific house you built. Every house can have a different number of windows. But a static field is like the BlueprintVersion written in the margin of the blueprint. It doesn't matter how many houses you build from that blueprint; they all refer back to that one single version number on the original paper.

I've seen juniors struggle with this when they try to track a "Total Players Joined" counter in a multiplayer game. If they make the counter a regular instance field, every new player object starts their own counter at zero. By making it static, every player instance shares the exact same counter in memory.

"Static is for Data" vs. "Static Classes for Pure Logic"

You can have static members inside a normal class, but you can also make the entire class static. This is where things get interesting. A static class cannot be instantiated—you can't use the new keyword on it. It essentially becomes a container for a group of related tools.

I generally reserve static classes for "pure functions"—logic that takes an input, returns an output, and doesn't need to remember anything about the past. The System.Math class is the gold standard here. You don't need to "create a Math object" to calculate a square root; you just ask the Math type to do it for you.

public static class PhysicsHelper
{
    public static double CalculateGravity(double mass) 
    {
        return mass * 9.81;
    }
}


"Static is Convenient" vs. "The Global State Trap"

Here is the professional advice I give to my mentees: just because you can make something static doesn't mean you should. Static members create "global state." This sounds great at first because you can access GameSettings.VolumeLevel from anywhere in your project without passing references around.

But global state is a nightmare for testing. If you have a static variable that tracks the state of a user's login, and you write a unit test that changes that state, every subsequent test in your suite is now running with that modified state. You'll find yourself chasing "ghost bugs" where a test fails not because the code is broken, but because a previous test left the static variable in a weird state. Use static for constants or stateless utilities, but be very cautious using it for data that changes frequently.




📋 Practical Task

Exercise: Implementing a Global Game-Time Synchronizer

You are building a game where multiple entities (Players, NPCs, Projectiles) need to know the total time elapsed since the game started. Instead of every entity tracking its own timer, you need a centralized system.

Your Task:

  • Create a static class named GameClock.
  • Inside GameClock, create a static field (or property) called ElapsedSeconds that stores a double.
  • Implement a static method called Tick(double deltaTime) that adds the provided deltaTime to the ElapsedSeconds.
  • Create a regular class called GameEntity. It should have a method PrintTime() that prints the current value of GameClock.ElapsedSeconds to the console.
  • In your main program, instantiate two different GameEntity objects. Call GameClock.Tick(1.5), then call PrintTime() on both entities to verify they both see the same updated time.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.