Understanding Classes in C#

Reading Time: 4 minutes

In today’s article I discuss Classes in C#. Classes are the most fundamental programming construct in .Net and an essential part of the OOP paradigm. Therefore it is crucial to understand classes in order to fully understand OOP concepts.

Definition

Formally, a class is defined as a user-defined type that is composed of field data and methods that operate on this data. A Class is a reference type, meaning a variable holding an instance of a class, stores a pointers or reference to the memory address where the values are stored.

Classes are not the same thing as Objects. A Class is a definition, or prototype that defines the properties, methods, etc. While an Object is an instance of a Class. An object contains state and behavior. Classes allow bundling of data (state) and functionality (behavior) in a single definition. Therefore allowing applications to be modeled after real-world entities. This is a very powerful concept.

Defining a Class

We begin with the simplest possible declaration of a class:

class Bicycle
{
}

Then add two properties, NumberOfGears and Make. NumberOfGears uses a feature called Auto-Property, which is simple syntactic sugar.

public class Bicycle
{
    // A property created using Auto-Property
    public int NumberOfGears { get; set; }

    // A property created without using Auto-Property
    private string _make;
    public string Make
    {
        get { return _make; }
        set { _make = value; }
    }
}

A Side Note: Class data should not be defined as public fields. It is best practices to use private fields and allow access via properties to preserve the integrity of the state data.

As I previously mentioned, an Object is an instance of a Class. An Object must be instantiated before it can be used. By instantiating an Object, memory is allocated for that Object. An Object is instantiated by using the new keyword, like so:

Bicycle schwinn = new Bicycle();

Constructors

Classes contain Constructors, which are methods that return void and can take 0 or more parameters. Constructors run when the class is instantiated. A constructor’s purpose is to assign initial values to the Class’ state. Each class is given a default constructor that takes 0 parameter and will assign each property its default value, based on its type. Once any constructor is defined for a Class, the default constructor is no longer available for that Class.

Let’s add a constructor to our Bicycle class.

public class Bicycle
{
    // A property created using Auto-Property
    public int NumberOfGears { get; set; }

    // A property created without using Auto-Property
    private string _make;
    public string Make
    {
        get { return _make; }
        set { _make = value; }
    }

    public Bicycle(int numberOfGears, string make)
    {
        Make = make;
        NumberOfGears = numberOfGears;
    }
}

Also notice that if we look at our initial instantiation example, it shows an error. This is because the default constructor is no longer available. Therefore the only constructor option now is the one explicitly define.

error - missing default constructor

Classes can have multiple Constructors. The criteria is that they have different method signatures, by either number of parameters, parameter type or a combination of both.

Constructors can also be chained, in other words, one controller can trigger a different controller. Here is an example of creating a parameter-less controller, which calls a second controller and passes default parameters to it.

public class Bicycle
{
    // A property created using Auto-Property
    public int NumberOfGears { get; set; }

    // A property created without using Auto-Property
    private string _make;
    public string Make
    {
        get { return _make; }
        set { _make = value; }
    }

    public Bicycle() : this(0, "N/A")
    {
        Console.WriteLine("Calling parameter-less constructor.");
    }

    public Bicycle(int numberOfGears, string make)
    {
        Make = make;
        NumberOfGears = numberOfGears;

        Console.WriteLine("Calling constructor with 2 parameters.");
    }
}

The best approach for constructor chaining is to start with the constructor that takes the largest number of argument and use it as the master constructor. Then other constructors will chain to the master constructor and provide default values for the parameters which are not part of the previous constructor in the chain.

The Static Modifier

To understand the Static keyword you must first know where is can be applied. The Static keyword can be applied to the following:

  • A Class definition
  • Properties and fields of a class
  • Methods of a class
  • A constructor

When applied to a Class, the class cannot be instantiated, in other words, you cannot use the new operator to instantiate a variable of the Static class type. A Static class is accessed directly by using the class name.

Static classes are generally used as a container for a set of stateless functions. A non-static class can contain static properties. The static properties are not accessible to instances of that class, in other words, static properties are only accessible by direct access to the class.

There is one static constructor that can be added to a class that contains static properties. The static constructor is defined by static <className>. Static constructors do not take an access modifier and do not have a return type, at all. The static constructor instantiates any static members of the class. The static constructor runs once, only when the class is instantiated for the first time.

Here is an example of our Bicycle class, where I add a static property to keep track of the NumberOfBikes instantiated.

public class Bicycle
{
    public static int NumberOfBikes { get; set; }
    // A property created using Auto-Property
    public int NumberOfGears { get; set; }

    // A property created without using Auto-Property
    private string _make;
    public string Make
    {
        get { return _make; }
        set { _make = value; }
    }

    static Bicycle()
    {
        NumberOfBikes = 0;
    }
    public Bicycle() : this(0, "N/A")
    { }

    public Bicycle(int numberOfGears, string make)
    {
        Make = make;
        NumberOfGears = numberOfGears;
        NumberOfBikes++;
    }
}

Now our application produces the following output:

As you can see above, the static constructor sets the value of NumberOfBikes to 0, then the non-static constructor increments it by 1. This confirms that the static constructor runs only once. Otherwise the NumberOfBikes would always reset to 1 (initial 0 plus increment) for each instantiation.

Where To Go From Here

This concludes my brief introduction to classes in C#. I have certainly not covered everything there is to know about classes. My intention is to provide a starting point, enough to build upon and learn more advanced concepts.

Microsoft provides excellent and in-depth documentation on this topic.

Leave a comment

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