Magical C# Constructors
Tags: csharp, oop, beginners, learning
Published: 2023-11-06 19:33:52

Hello! Welcome back to another magical post about Object Oriented Programming with C#.

This post will introduce the concept of **constructors** and how they are helpful in creating **objects**.

The main topics discussed are: 
- Default values
- Default constructors
- Constructor overloading
- The 'this' keyword
- The 'base' keyword

Assuming you have already read my post about [C# classes and objects](https://dev.to/elliezub/magical-c-classes-3heg), let's move on to the wizard examples!🧙🏻‍♀️ 
<br>

### Constructors

First, it's important to answer the question: _what is a constructor?_

- A constructor is a special method in a class that sets up and initializes a new object, ensuring that all its properties are given the right starting values.

If you want more info about constructors, it's beneficial to get a few different examples & points of view. Here are some good resources to learn more:

- [W3Schools constructors - free course](https://www.w3schools.com/cs/cs_constructors.php) 
- [C# Constructors - article](https://www.csharptutorial.net/csharp-tutorial/csharp-constructors/)
- [Codecademy's C# Classes & Objects - free course](https://www.codecademy.com/learn/learn-c-sharp-classes-objects-interfaces-and-inheritance)  
- [Microsoft's C# Docs](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/constructors)

---

### Wizard Class without a constructor

Remember our "Wizard" class from the [last post](https://dev.to/elliezub/magical-c-classes-3heg)? If not, that's ok, here it is: 

```csharp
public class Wizard
{
    private int age;

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

    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}!");
    }
}
```

In this example, if we wanted to add a new "Wizard" we would create a new "draco" object like this: 

```csharp
Wizard draco = new Wizard
{
    Name = "Draco Malfoy",
    House = "Slytherin",
    Age = 11,
    WandType = "Hawthorn with a unicorn hair core",
    Pet = "Eagle Owl"
};
```

But there's an easier way! and that's why we use **constructors**.
<br>

### Wizard class with a constructor

Here's how the Wizard class would look with a constructor: 

```csharp
public class Wizard
{
    private int age;

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

    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; }

    // constructor 
    public Wizard(string name, string house, int age, string wandType, string pet)
    {
        Name = name;
        House = house;
        Age = age;
        WandType = wandType;
        Pet = pet;
    }

    // Method to represent casting a spell
    public void CastSpell(string spellName)
    {
        Console.WriteLine($"{Name} casts {spellName}!");
    }
}
```

This makes it much easier to create a new "Wizard" aka a new object:

```csharp
Wizard draco = new Wizard("Draco Malfoy", "Slytherin", 11, "Hawthorn with a unicorn hair core", "Eagle Owl");
```

<img width="100%" style="width:100%" src="https://media.giphy.com/media/ygx8EYsdRkNpu/giphy.gif">


### Default values

_But what if we don't know everything about a new "Wizard" at Hogwarts?_

Could we just, not enter that info?

Well, if we did that, this is what would happen.

First, we have our constructor:

```csharp
public Wizard(string name, string house, int age, string wandType, string pet)
    {
        Name = name;
        House = house;
        Age = age;
        WandType = wandType;
        Pet = pet;
    }
```

Then we try to create a new Wizard:

```csharp
Wizard neville = new Wizard("Neville Longbottom", "Gryffindor", 11, "Cherrywood with a unicorn hair core");
// Missing the 'pet' parameter
```

_So.. what happens if we don't include Neville's pet toad?_

We will see this error 😱

```
error CS7036: There is no argument given that corresponds to the required formal parameter 'pet' of 'Wizard.Wizard(string, string, int, string, string)'
```

_So.. how can we avoid this?_ 🙄

Well, that's what **default values** are for!

```csharp
// look! some default values!
public Wizard(string name = "Unknown", string house = "Unassigned", int age = 11, string wandType = "Standard", string pet = "Unknown")
    {
        Name = name;
        House = house;
        Age = age;
        WandType = wandType;
        Pet = pet;
    }
```

This way, if we choose to omit, or forget to assign a value, the code will still run with the value being assigned to the default value. 

<img width="100%" style="width:100%" src="https://media.giphy.com/media/hqBsV4bE9LGz6/giphy.gif">

### Default constructors

Another important topic is **default constructors** although they sound similar to default values, they serve a different purpose.

They are the simplest form of constructors which don't take any arguments.

In some cases, a default constructor might set properties to their default values, or it might leave them to be set later.

For example, if you want to create a "Wizard" but you don't have all the necessary info, a default constructor allows you to instantiate the object and fill in the details later:

```csharp
public Wizard()
{
    // Initialize with default values
    Name = "Unknown";
    House = "Unassigned";
    Age = 11; // Default starting age for Hogwarts students
    WandType = "Standard";
    Pet = "Unknown"; 
}
```

Then you can create a new "Wizard" like this: 

```csharp
Wizard ginny = new Wizard();
```

Since "ginny" is a new student, we still don't have all of her details. They must be assigned as they become known to the school.

```csharp
// When Ginny is enrolled, we know her full name
ginny.Name = "Ginny Weasley";

// Then we assign the rest of the properties as we become aware of them

// After the sorting hat ceremony we find out she is sorted into Gryffindor!
ginny.House = "Gryffindor";

// Then she must register her wand
ginny.WandType = "Yew with a phoenix feather core";

// Later, when she gets a pet, we would update her pet info
ginny.Pet = "Arnold the Pygmy Puff";
```

_But this seems a bit tedious, why would I ever use this method over the previously described methods?_

Well, a default constructor can be particularly useful when you need to create an object without immediately supplying detailed information, it provides the ability to set properties at a later time. 

This is exactly what we did with "ginny", we didn't have all of the information at first so we had to add the new information as we became aware of it.
<br>

### Constructor overloading

Similar to default values and default constructors, there is something called constructor overloading. We do this when we might not have all the details about a wizard, or maybe we have wizards with different sets of known attributes.

So.. **_what's the difference between all three?_**

**Default values** and **default constructors** are useful when you want to fill in missing information automatically. However, **constructor overloading** makes it possible to create objects with varying sets of initial information from the very beginning.

```csharp
public class Wizard
{
    public string Name { get; set; }
    public string House { get; set; }
    public string Pet { get; set; }
    public string WandType { get; set; }
    // Intentionally excluding Age for readability

    // Constructor for a wizard without a pet
    public Wizard(string name, string house, string wandType)
    {
        Name = name;
        House = house;
        WandType = wandType;
    }

    // Constructor for a wizard with a pet
    public Wizard(string name, string house, string wandType, string pet)
    {
        Name = name;
        House = house;
        WandType = wandType;
        Pet = pet;
    }

    // Constructor for a foreign wizard where we only know the name and wand type
    public Wizard(string name, string wandType)
    {
        Name = name;
        WandType = wandType;
        // House and pet might be unknown
    }
}

// Wizard with a pet
Wizard hermione = new Wizard("Hermione Granger", "Gryffindor", "Vine wood with a dragon heartstring core", "Crookshanks");
// Foreign wizard
Wizard viktor = new Wizard("Viktor Krum", "Hornbeam");
```
_Can you use default values, default constructors, and constructor overloading at the same time?_

Yes! At the end of this post, there will be an example of an ultimate "Wizard" class using everything mentioned in this post. 
<br>

### 'this' keyword

What's **_this_**?

Well, the "this" keyword has two main usecases. 

**1.** To avoid confusion ( this.Name = name; )
```csharp
public class Wizard
{
    public string Name { get; set; }

    // Constructor using the 'this' keyword to differentiate between
    // the parameter 'name' and the class property 'Name'
    public Wizard(string name)
    {
        this.Name = name; // 'this.Name' refers to the property 'Name' of the current instance
        // Name = name; can get confusing, so using this.Name can be a bit clearer sometimes
    }
}
```
**2.** Constructor chaining ( : this(name) )

```csharp
public class Wizard
{
    public string Name { get; set; }
    public string House { get; set; }
    public string WandType { get; set; }

    // Constructor that takes only Name
    public Wizard(string name)
    {
        this.Name = name;
    }

    // Constructor that takes Name and House, reusing the first constructor
    public Wizard(string name, string house) : this(name)
    {
        this.House = house;
    }

    // Constructor that takes Name, House, and WandType, reusing the second constructor
    public Wizard(string name, string house, string wandType) : this(name, house)
    {
        this.WandType = wandType;
    }
}
```
_**What's the point of constructor chaining?**_

Constructor chaining allows a constructor to call another constructor within the same class to set things up, which keeps the code simple and avoids repetition. Neat, right?
<br>

### 'base' keyword

Another keyword?? 🤨

Yes.. but this one is pretty easy!

It's very similar to the "this" keyword, except it can help chain info from **other** classes.

According to our previous examples, the "Wizard" class represents all students or faculty members at Hogwarts. However, students may also participate in school sports, like Quidditch, which requires keeping track of additional details like the player's position. 

So we would also need to create a "QuidditchPlayer" class that extends the Wizard class because it needs to include all the standard wizard information, plus these extra sports-related attributes. 

This is how that would look:

```csharp
// Base class for any wizard at Hogwarts
public class Wizard
{
    public string Name { get; set; }
    public string House { get; set; }

    public Wizard(string name, string house)
    {
        Name = name;
        House = house;
    }
}

// Derived class for a Quidditch player
public class QuidditchPlayer : Wizard
{
    public string Position { get; set; }

    // Constructor sets up a Quidditch player, using 'base' to include the basic wizard setup info
    // The 'base' keyword passes name and house to the Wizard constructor
    public QuidditchPlayer(string name, string house, string position) : base(name, house) 
    {
        Position = position;
    }
}

QuidditchPlayer harry = new QuidditchPlayer("Harry Potter", "Gryffindor", "Seeker");
```

<img width="100%" style="width:100%" src="https://media.giphy.com/media/uma9yIh0ghkFa/giphy.gif">

That's it for basic constructors. Here are all of the things we learned together in an ultimate "Wizard" class!
<br> 

### ULTIMATE WIZARD CLASS!

```csharp
public class Wizard
{
    public string Name { get; set; }
    public string House { get; set; }
    public string WandType { get; set; }

    // Default constructor
    public Wizard()
    {
        Name = "Unknown";
        House = "Unassigned";
        WandType = "Standard";
    }

    // 1. Constructor that takes only Name but inherits the defaults from the default constructor
    public Wizard(string name) : this()
    {
        Name = name;
    }

    // 2. Constructor that takes Name and House, reusing constructor 1
    public Wizard(string name, string house) : this(name)
    {
        House = house;
    }

    // 3. Constructor that takes Name, House, and WandType, reusing constructor 2
    public Wizard(string name, string house, string wandType) : this(name, house)
    {
        WandType = wandType;
    }
}

public class QuidditchPlayer : Wizard
{
    public string Position { get; set; }

    // Default constructor for QuidditchPlayer
    public QuidditchPlayer() : base()
    {
        Position = "Chaser";
    }

    // Constructor chaining is used here as well, reusing Wizard's constructor
    public QuidditchPlayer(string name, string house, string wandType, string position) : base(name, house, wandType)
    {
        Position = position;
    }
}

// A lesser-known wizard with minimal information
Wizard blaise = new Wizard("Blaise Zabini");

// A member of the Order of the Phoenix with some details known
Wizard mundungus = new Wizard("Mundungus Fletcher", "Gryffindor");

// A fully detailed wizard
Wizard hermione = new Wizard("Hermione Granger", "Gryffindor", "Vine wood with a dragon heartstring core");

// Quidditch player with all properties known
QuidditchPlayer harry = new QuidditchPlayer("Harry Potter", "Gryffindor", "Holly wood with a phoenix feather core", "Seeker");

// Example output:
Console.WriteLine($"Wizard: {blaise.Name}, House: {blaise.House}, Wand: {blaise.WandType}");
// Output: Wizard: Blaise Zabini, House: Unassigned, Wand: Standard

Console.WriteLine($"Order Member: {mundungus.Name}, House: {mundungus.House}, Wand: {mundungus.WandType}");
// Output: Order Member: Mundungus Fletcher, House: Gryffindor, Wand: Standard

Console.WriteLine($"Wizard: {hermione.Name}, House: {hermione.House}, Wand: {hermione.WandType}");
// Output: Wizard: Hermione Granger, House: Gryffindor, Wand: Vine wood with a dragon heartstring core

Console.WriteLine($"Quidditch Player: {harry.Name}, House: {harry.House}, Wand: {harry.WandType}, Position: {harry.Position}");
// Output: Quidditch Player: Harry Potter, House: Gryffindor, Wand: Holly wood with a phoenix feather core, Position: Seeker
```

--- 

### Challenge (optional)

If you're up for it, I challenge you to make your own constructor that includes:

- Default values
- A default constructor
- Constructor overloading
- The 'this' keyword
- The 'base' keyword

Theme ideas: 
- **Astronomy:** Classes for celestial objects like Star, Planet, and Asteroid. Properties could include mass, composition, and orbit details.
- **Magical Beasts:** A MagicalBeast base class with properties like rarity, danger level, and magical abilities. Subclasses could include Dragon, Phoenix, Basilisk, each with special traits or abilities.

Don't be afraid to ask your friendly neighborhood chatGPT for more ideas that align with your personal interests😄

If you actually do the challenge, please send me the link to your code. I would love to see your solution!

---

<img width="100%" style="width:100%" src="https://media.giphy.com/media/pgTUboKO6i08/giphy.gif">

Well, that's it for this post! If you've made it this far, Hermione certainly would be proud of you. 

In the future, I will be making part 2 which will be about "static constructors", "copy constructors", and "destructors". (Thought it would be a bit overwhelming to add those here)

If you're looking for more resources to learn how to code check out my [Free Coding Resources](https://elliezub.github.io/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](https://twitter.com/elliezub).

Happy coding!