Lesson 11.1 – Using a static class

Lesson Objectives

At the end of this lesson, you will know…

  • What a static class is, and how to create one.
  • When you want, and don’t want, to use static classes

 

What is a static class?

All the classes we’ve created so far have been public classes. That means they are visible in all of your program. However, in order to use one of them, you need to create an object of the class. Then you work with that object.

A static class is one that is always available to the rest of your program – you don’t need to create an object from it. In fact, you can’t create an object from a static class. It’s just there.

A static class is a place to hold shared resources (variables and methods), since there will only be the one “instance” of it, and everything else in your program will use that one, shared set of methods and variables.

 

Why would you need a static class?

For our game, we need to store some things that will be used in several places in the program.

Things like the list of locations, the types of items, the types of monsters, etc. This information is never going to change. We’re going to populate these lists at the start of the game, and never change it. We’re also going to use those lists in several places in the game.

Using a static class to hold all this information is one way to make all this information available everywhere.

 

When else would you use a static class?

Another thing you can do with a static class (and a static variable) is to hold values such as a system-wide counter.

Let’s say you want a program to hand out unique, sequential numbers to the people who use it.

You could create a static NumberAssigner class, with a static GetNextNumber method, that keeps track of a static _nextNumber variable.

When you start the program, _nextNumber has a value of 0.

When a user calls the GetNextNumber method, the code adds 1 to _nextNumber and returns the value (in this case, 1) to the program. The next time the GetNextNumber method is called, it adds 1 to _nextNumber (resulting in 2 this time) and returns 2 to the program.

 

What problems can happen with static classes?

The problem with static methods and variables, is that sometimes you don’t want a shared resource, you want each user to have their own copy of the object or variable.

The game we’re creating is a single-player one. So, we don’t really have a problem using static variables.

However, if we were to make a UI for this game a website on the Internet, we might have several people playing it at the same time.

So, let’s say we stored the player’s current hit points somewhere as a static variable – CurrentHitPoints.

When player A is attacked, the program would subtract their damage and change the value of CurrentHitPoints. But if a different player did something in the game (attacked a monster or healed themselves with a potion), since we only have a static, single, shared CurrentHitPoints variable, they’d be using the value from player A, and not their real current hit points value.

That’s how static classes and variables can be dangerous. When you use a static variable to hold a value, make sure it’s one that you really want to be shared for every user.

 

Populating our game world in a static class

Now that you have an understanding of static classes and variables, we’re going to create a “World” class to hold lists of all the things in our game – locations, items, monsters, and quests.

Since we’re only going to read from it, once we do the initial population of the values, it’s OK to use a static class.

Step 1: Start Visual Studio Express 2013 for Desktop, and open the solution.

Step 2: Create a new class by right-clicking on the Engine project and selecting “Add”, then “Class…”. Name the class “World.cs”

Step 3: Copy the code for the class from here: https://gist.github.com/ScottLilly/803df1021fbc404b38f5

 

What does the code do?

The purpose of the World class is to have one place to hold everything that exists in the game world. In it, we’ll have things such as the monster that exist at a location, the loot items you can collect after defeating a monster, etc. It will also show how the locations connect with each other, building our game map.

GameMap

Here is what is happening in the different parts of the World class.

Lines 11 – 14: Static list variables. These work similar to the properties in a class. We’ll populate them with all the things in our game world, then read from them in the rest of the program.

Line 16 – 42: Constants. Constants look, and work, like variables, except for one big difference – they can never have their values changed.

We’re going to use these constants, which have a sort-of English name, so we don’t have to remember the numeric ID for each of the different games objects. Without them, if we wanted to create a giant spider for the player to fight, we’d need to remember that the giant spider monster has an ID value of 2. With the constants, we can say, get me a monster where the ID equals MONSTER_ID_GIANT_SPIDER.

If you don’t fully understand how we’ll do that, it should become clearer when we get to the lesson where we start having the player move around and we need to lookup locations, quests, monsters, and items.

Lines 44 – 50: This is the static constructor. You might be thinking, “Wait! We can’t instantiate a static class, so why does it have a constructor? After all, that’s what a constructor is used for – instantiating an object!”

With a static class, the constructor code is run the first time someone uses anything in the class. So, when we start the game and want to display information about the player’s current location, and we try to get that data from the World class, the constructor method will be run, and the lists will get populated.

Inside the constructor, we call the four methods to populate the different lists. We don’t need to have separate methods, and we could have put all the code from lines 48 through 169 into the constructor. But breaking them up makes them easier to read and work with.

Lines 52 – 173: These are the methods we use to create the game objects and add them to the static lists.

By calling the Add() method on a list variable or property, we add an object to that list.

Look at line 54. Here we are adding a new Weapon object to the Items list. When we call “new Weapon()”, the constructor of the Weapon class returns a Weapon object with the parameters passed in. Since that’s all inside “Items.Add()”, that object gets added to the Items list.

You might hear that called “inlining”, since we did multiple things (created the value and added it to the list), all in one line.

On line 68, we create a new Monster object and save it to the variable “rat”. On lines 69 and 70, we add items to the (list) property of PotentialLootItems that you might find on the rat. Then, on line 80, we add the rat variable to the static Monsters list.

Lines 175 – 225: These methods are ones we can call to get values from the static lists. We could access the lists from lines 7 through 10 directly, since they are public. But these “wrapper” methods make it a little clearer exactly what we want to do.

We pass in the ID of the object we want to retrieve from its list (by using the constants from lines 16 through 42). The method will look at each item in the list (using the “foreach”) and see if the ID we passed in matches the ID of the object. If so, it returns that object to us. If we get to the end of the list, and nothing matches (which should really never happen), the method returns “null” – nothing.

 

Summary

Now we have a populated “world” for the game. We can use the static methods from this static class at any place in the rest of our program, and get the information we need about the objects in our game world.

 

Click to view source code

World.cs

 

Source code for this lesson

Source code on GitHub

Source code on Dropbox

 

Next Lesson: Lesson 12.1 – Add the remaining UI controls

Previous lesson: Lesson 10.1 – Creating collections of objects

All lessons: Learn C# by Building a Simple RPG Index

125 thoughts on “Lesson 11.1 – Using a static class

  1. Hey Scott.

    What is your oppinion about making 4 static classes (monsters, items, quests and locations) instead of one world class?
    For bigger games it looks easyer to read. (lets pretend databases dont exsist) 🙂

    1. You could do that, but I like the idea of having a single static class that holds the complete “world”.

      To make World.cs smaller, I might create four factory classes (MonsterFactory, ItemFactory, etc.). Those factory classes would each have one static function – like “GetAllMonsters()”. That function would create a list of all monster objects and return that list. The World class would call those functions, instead of calling the current “Populate” functions inside World.cs, and use the returned lists to populate the static list in World.cs.

      But, this is one of those things that would mostly depend on the programmer’s personal preference.

  2. I appreciate all these lessons, your updates, and replies to all the questions. I can tell you are very passionate and dedicated about teaching and programming seeing that you STILL answer questions and reply to them. It’s an amazing feat to say the least really. But I had a general question about this lesson particularly. The code that you had us copy from Github is huge and feels like a giant skip between the lessons. I know it cost a heck of a lot of lessons to cover all those but why did you decide that this is the way to continue on with the lessons?

    Also, I’m still very confused about the constructor class and I’ve been checking lots of places to get an answer but they all sound similar to me and are still very difficult for me to grasp. Could you kindly let me understand what constructor is like I’m 5 years old in one or two sentences? Doesn’t need to be precise or professional I just really want to get a feel of understanding the constructor function.

    Thank you!

    1. This isn’t one or two sentences, but, I hope it will help you.

      Remember one of the earlier lessons about classes and objects. A class is a definition of what is in an object. So, a class is like a blank form you need to fill out to open a bank account. You don’t actually have the bank account until you fill out the form and the bank creates the account – like creating/instantiating an object from a class.

      A constructor is just a function used to create/instantiate an object from a class. So, when you want to create a Player object (for example), you call the Player class constructor. If the Player class does not have a constructor function, you instantiate it by saying “new Player();”. This is called “using the default constructor”, because it is the method to use for all non-static classes that do not have a constructor function.

      Sometimes the programmer wants to control creating instances of a class – usually because they want to ensure the object has some values filled in when it is constructed. So, the programmer would create a constructor function for the class. When you want to instantiate a Player object, you need to pass in values for the parameters that are in the constructor. For example, if the programmer wants all Player objects to have have a name, they could create a constructor function like this:

      public Player(string name)
      {
      Name = name; // Set the "Name" property to the value passed in as the "name" parameter
      }

      It is possible for a class to have more than one constructor function, if the programmer wants to provide different ways to instantiate an object for the class.

      Static classes are a little different. They cannot be instantiated – never. They are classes that always exist in the project. You can use their static functions and static properties without ever instantiating an object.

      For static classes, you can define a function that is run the first time any of its functions or properties is used. In the World class, this is the function that starts with “static World()”. This function runs the first time any other part of the program tries to use any of the static functions, like ItemByID, MonsterByID. This function populates the static lists, which are used by the static functions. It only needs to run the first time because the static lists remain populated, for the next time one of the static functions is called.

      Does that make sense?

  3. I have been struggling to learn the exact definition of static classes and you just explained it perfectly and easily. Hands down the best tutorial for beginners.

  4. I am transitioning from VBA to C#, and this tutorial has been great so far in helping me understand the basics of C# while also learning how to use Visual Studio.

    I am curious, in this lesson, would it be possible to replace the “public static Thing ThingByID(int id)” with something like “public static ??? ByID(int id, ??? classType)” with a switch that would determine the appropriate list to look in based on the classType passed?

    Maybe the complexity of doing something like that would outweigh the benefits of removing the duplication found in those methods.

    1. Hi Byron,

      You could do that with generics. You would probably want to implement the “repository design pattern”. You can see a sample way to do that here: https://cpratt.co/truly-generic-repository/.

      This solution usually involves more complexity than I like. However, there are several ORMs (Object-relational mapping) libraries that do this when they hide the database access. You setup a data repository, make calls to it, and it manages all the read/write/update/delete commands for the database. StackOverflow shows a very basic implementation here: https://stackoverflow.com/questions/6543436/nhibernate-repository.

Leave a Reply

Your email address will not be published. Required fields are marked *