The Construction Begins
C# Constructors are the building blocks that enable you to create classes and struct-s, set default values, limit instantiation, and more.
Aug 6, 2019 • 7 Minute Read
Introduction
Constructors are the building blocks that enable you to create classes and struct-s. A class or struct can have multiple constructors. These constructors allow the developer to set default values, limit instantiation, and write applications/code that is easy to read/maintain/extend.
Constructors
If you do not provide any constructors for your class or struct, C# is going to create one by default. This, in turn, instantiates the object and sets member variables to the default values based on their datatypes. In the Default Values Table you will find the list of default values based on the types with which C# works. Not providing the constructor means that C# will rely on an implicit, parameter-less constructor to automagically initialize each field of a value type to the default values, based on the above table.
Constructors are special methods where the name is the same as its type. To speak more professionally, the method signature only consists of the method name and its parameter list, and it does not include a return type. This is an example of that:
public class ProgrammingLanguage
{
private string name;
private double version;
public ProgrammingLanguage(string languageName, double languageVersion)
{
name = languageName;
version = languageVersion;
}
}
There are two ways to implement a constructor. One is a single line statement, like the example below, and the other is the more talkative example above. Both have their advantages and disadvantages. Let's explore the single like statement a.k.a. expression body definition.
public class Language
{
private string languageName;
public Language(string name) => Name = name;
public string Name
{
get => languageName;
set => languageName = value;
}
}
This expression definition assigns the argument to the languageName.
Static Constructors
The previous examples were instance constructors that created a new object. The classes and structs can also have static constructors that initialize static members of a specific type. These are usually parameterless. If you do not provide a static constructor to initialize the static fields, the C# compiler recognizes it and these fields are initialized to their default values based on the Default Values Table. Let's look at an example of that.
The static constructors are used to initialize any static data or just to perform an action/calculation that needs to be performed once. It is called automagically before the first instance is created or any static members are referenced.
public class Python : Language
{
private static double minimumVersion;
public Python(string creator, string languageType) : base(creator, languageType)
{ }
static Python()
{
minimumVersion = 3.8;
}
}
This other example uses the expression body definition to achieve the same.
public class Ruby : Language
{
private static double minimumVersion;
public Ruby(string creator, string languageType) : base(creator, languageType)
{ }
static Ruby() => minimumVersion = 18;
}
Typical usage:
- Use the Logger class when a class uses some file to write logs or data.
- Use the Wrapper class for unmanaged code.
- Enforce runtime checks of parameters which cannot be checked via compile-time constraints.
Instance Constructors
These constructor types are used when you initialize any instance member variable using the new expression to create an object of a class. It's important, in order to initialize a static class or static variable in a non-static class, that you define a static constructor.
Here is an example of an instance constructor that is called parameterless.
class VillageCoordinates
{
public double lat, lng;
// constructor
public VillageCoordinates()
{
lat = 0;
lng = 0;
}
}
If you are using public fields, you need to be aware that it is not really recommended. The public fields allow any method anywhere in the program - unrestricted and unverified access to the given objects’ internal workings. These members should generally be private and should be accessed only through class properties and methods.
Let's add another constructor which takes two arguments.
public VillageCoordinates(double lat, double lng)
{
this.lat = lat;
this.lng = lng;
}
The instance constructor is called whenever an object based on the VillageCoordinates class is created. It is often useful to provide different types of constructors as your application matures to ease the creation of new objects.
Now you are able to create villages with default or specific initial values.
VillageCoordinates Village1 = new VillageCoordinates();
VillageCoordinates Village2 = new VillageCoordinates(10.4,20.2);
When a class does not have a constructor, the parameterless is used based on the default values of the members.
Private Constructor
This is a special type of instance constructor. The main instance for usage is when your classes only have static members. If a class has one or more private constructors and no public constructors, other classes are not able to create instances of this class; except the nested classes inside this class.
For example:
class Vehicle
{
private Vehicle() {}
public static int wheels = 4 ;
}
If you declare an empty constructor, the C# compiler will not dynamically generate a parameter-less constructor. If you do not use an access modifier with the constructor, it will also become a private constructor by default. Using the private keywords makes it obvious for developers by explicitly stating the type.
Private constructors are very similar as to how the Math class works. It prevents the creation of instances when there is no instance field or method, or when a method is called to obtain an instance of a class.
Conclusion
This guide walked you through the nifty details of the different types of constructors provided to you by C#. These constructors came to the language over time to bridge the need for the new requirements this language was stretched to be used. By understanding the rules and requirements of these different constructors, you will become prepared to face any challenge about your new application and be able to write efficient, well structured, and robust code.