Magical C# Classes

Ellie - Oct 26 '23 - - Dev Community

If you're like me and can't seem to wrap your head around "classes" then I hope these magical examples can serve as some kind of reference for the both of us!

In this post, I'll be using some wizard-themed examples to try and make a reference for myself and others so we can finally "get" classes.

This post will just cover the basics of classes and objects, there will be further posts explaining more advanced topics.

Classes and Objects

First of all, why do we even need classes?

To put it simply, they keep related bits of code and info together, so everything is neat and easy to find. Pretty convenient, right?

Of course, there's a lot more to it than that, I suggest checking out some of these resources to learn more about classes and objects.

After you have an idea about what classes and objects are, check out the "Wizard" class below👇


Wizard Class

Imagine you wanted to represent every witch or wizard in the Harry Potter universe. You could create a class to define their common characteristics.

public class Wizard
{
    private int age; // This is a backing field for the Age property

    // what's a backing field??😅 see Example 1 below 

    // Properties
    public string Name { get; set; }
    public string House { get; set; }
    public string Pet { get; set; }

   // what the heck do get and set do?? see Example 2

    public int Age
    {
        get 
        { 
            return age; 
        }
        set 
        {
            if (value >= 11 && value <= 150)
            {
                age = value;
            }
            else
            {
                Console.WriteLine("Invalid age for a wizard at Hogwarts.");
            }
        }
    }
    public string WandType { get; set; }

    // Methods
    public void CastSpell(string spellName)
    {
        Console.WriteLine($"{Name} casts {spellName}!");
    }
}

Enter fullscreen mode Exit fullscreen mode

Here, "Wizard" is a class that has properties like "Name", "House", "Age", and "WandType". It also has the method "CastSpell" to represent the action of a witch or wizard casting a spell.

The "age" field is private and is used to store the actual value of a wizard's age. When we want to set or get the age of a wizard, we use the public "Age" property.

The set accessor in the "Age" property contains logic to validate the age. If someone tries to set an age value less than 11 or more than 150, the class will print an error message, and the age won't be changed.

But why should we have a private AND a public Age? Why do we even need a backing field?

Look at this part of the "Wizard" class again:

private int age; // Backing field

public int Age
{
    get { return age; }
    set 
    {
        if (value >= 11 && value <= 150)
        {
            age = value;
        }
        else
        {
            Console.WriteLine("Invalid age for a wizard at Hogwarts.");
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

We are using a backing field ("age"). The "age" variable is the backing field for the "Age" property. The backing field is necessary here to store the value of "Age" when it's set, and to return the value when it's accessed.

The key point about using a backing field is that it allows you to have control over how the value is stored and accessed, enabling you to add additional logic (like validation) as needed.

If you were to try and define the "Age" property without a backing field:

public int Age
{
    get { return Age; }
    set 
    {
        if (value >= 11 && value <= 150)
        {
            Age = value;
        }
        else
        {
            Console.WriteLine("Invalid age for a wizard at Hogwarts.");
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

You would end up with a recursive call that would result in a StackOverflowException. This happens because when you try to get or set the age, it just ends up trying to get or set the age again, creating an infinite loop.

Using a backing field avoids this issue, because in the get and set accessors, we have a separate variable (age), not the property itself.

If this is still confusing, check out Example 1 below.

Wizard Objects

Now, if we want to represent both Harry Potter and Hermione Granger in our program, we need to create two objects (or instances) of the "Wizard" class:

Wizard harry = new Wizard
{
    Name = "Harry Potter",
    House = "Gryffindor",
    Age = 17,
    WandType = "Holly with a phoenix feather core",
    Pet = "Hedwig the owl"
};

Wizard hermione = new Wizard
{
    Name = "Hermione Granger",
    House = "Gryffindor",
    Age = 17,
    WandType = "Vine wood with a dragon heartstring core",
    Pet = "Crookshanks the cat"
};

harry.CastSpell("Expelliarmus");
// Output: Harry Potter casts Expelliarmus!

Console.WriteLine($"{hermione.Name} has a pet named {hermione.Pet}");
// Output: Hermione Granger has a pet named Crookshanks the cat

Enter fullscreen mode Exit fullscreen mode

In this example, "harry" and "hermione" are objects of the Wizard class. We set their properties individually, giving each wizard their own unique characteristics. After that, Harry casts a spell using the "CastSpell" method, and we also display the name of Hermione’s pet cat, Crookshanks, using the properties of the "hermione" object.


Examples:

Example 1: Backing field

Imagine a backing field as Tom Riddle’s diary.

  1. Diary (Backing Field): Just like how Tom Riddle put his thoughts and secrets into the diary, your private data is stored securely. It’s meant to be accessed and modified only within safe and controlled conditions.

  2. Tom Riddle's manifestation (Property): If someone at Hogwarts, let's say Ginny, wants to delve into the diary’s mysteries, she wouldn’t directly read from its pages. Instead, she would interact with Tom Riddle’s manifestation, which represents the property in C#. Depending on the circumstances, Tom might alter the information, hold back details, or even choose to remain silent.

In coding:

  • The diary is like the backing field. It holds the actual data.

  • Tom’s manifestation acts as the property, controlling access to the diary’s content. Other parts of the code (aka other characters in the story) must communicate with Tom to access or modify the diary's content. However, the ability to access or change the content is based on specific conditions.

Example 2: Accessors (get and set)

Think of the thermostat in your home:

  • get: When you look at the thermostat, you can see the current room temperature. This is like the get accessor – it allows you to view the value.

  • set: If you want the room to be warmer or cooler, you adjust the thermostat to the desired temperature. However, there are limits on how high or low you can set the temperature. For example, it might only go as low as 50°F and as high as 90°F. If you try to set it outside these limits, it won't let you. That’s how the set accessor works, the information needs to be validated before it is actually set.

In our "Wizard" class, the "Age" property is similar. When we "get" the age, it's like checking the current temperature. But when we "set" the age, we ensure it's a valid age (between 11 and 150), just as the thermostat ensures the temperature is within its limits.

Here's a simple wizard example about how get and set work:

public class Wizard
{
    private string favoriteSpell;  // Backing field

    public string FavoriteSpell
    {
        get
        {
            return "The favorite spell is: " + favoriteSpell;
        }
        set
        {
            if (string.IsNullOrEmpty(value))
            {
                Console.WriteLine("A wizard must have a favorite spell!");
            }
            else
            {
                favoriteSpell = value;
            }
        }
    }
}

// Using the class
Wizard ron = new Wizard();
ron.FavoriteSpell = "Wingardium Leviosa";  
// Sets rons favorite spell
Console.WriteLine(ron.FavoriteSpell);      
// Gets rons favorite spell 
// Output: The favorite spell is: Wingardium Leviosa

Enter fullscreen mode Exit fullscreen mode

In this example:

  • The "FavoriteSpell" property uses get to retrieve and display the wizards favorite spell.
  • The set accessor checks if the provided spell is null or empty. If it is, it gives a message that a wizard must have a favorite spell; otherwise, it sets the favorite spell.

Also, it’s important to note that C# has a shortcut for when you don’t need extra logic in your get or set. Instead of writing out the whole thing with a backing field and validation, you can do something like this:

public string Wand { get; set; }
Enter fullscreen mode Exit fullscreen mode

Here, a hidden backing field is automatically created for the "Wand" property. This keeps code concise, but if you need to add validation or other logic, you would need to create a backing field and switch to the full property syntax.


Well, thats all for this post. I recommend trying to make your own classes and objects. By doing this, you'll deepen your understanding and see how everything fits together.

If you have any suggestions for how to improve this post or notice anything I have excluded that should be considered basic knowledge when it comes to classes and objects please let me know 😄

If you're looking for more resources to learn how to code check out my Free Coding Resources site, it has links to a bunch of my favorite courses/resources!

If you have any questions or want to connect, the best place to reach me is on Twitter/X.

Happy coding!

. . . . . . . . .