A good understanding of constructors is a prerequisite for
all class designers. This article covers the basic concepts of constructors in
C# and discusses constructor overloading, types of constructors, and the
behavior of constructors in inheritance, with some sample programs.
What is a Constructor?
A constructor is a member function that has the same name as
the class name and is invoked automatically when the class is instantiated. A
constructor is used to provide initialization code that gets executed every
time the class is instantiated.
Points to be noted on constructors:
·
Constructors cannot be "virtual".
·
They cannot be inherited.
·
Constructors are called in the order of inheritance.
·
If we don't write any constructor for a class, C# provides an
implicit default constructor, i.e., a constructor with no argument.
·
Constructors cannot return any value.
·
Constructors can be overloaded.
The syntax for a constructor is as follows:
[modifier] name (parameters)
{
// constructor body
}
As per the C# specification, a constructor can have the
following modifiers.
public
protected
internal
private
extern
These modifiers are explained later in the article.
Types of Constructors
Constructors in C# can be of two types:
1. Static or class constructors
2. Non–static or instance constructors
Static Constructors
A static constructor or class constructor gets called when
the class is instantiated or a static member of the class is used for the first
time.
The following points hold good for static constructors:
·
A Static constructor cannot be overloaded.
·
It should be without parameters and can only access static
members.
·
It cannot have any access modifiers.
·
The static constructor for a class executes only once in an
application domain.
·
Static constructors cannot be chained with other static or
non-static constructors.
In the program that follows, the static constructor is
invoked once the static variable of the class is referenced.
Listing 1
using System;
class Test
{
private static int i;
static Test()
{
Console.WriteLine ("Static Constructor.");
}
public static int Assign
{
set
{
i = value;
}
get
{
return i;
}
}
}
class Sample
{
public static void Main()
{
Test.Assign = 2;
}
}
The following program shows that a static constructor for a
class is invoked before an instance constructor.
Listing 2: Static Constructor Executes Before an Instance
Constructor
using System;
class TestClass
{
static TestClass ()
{
System.Console.Write("Static ");
}
public TestClass ()
{
System.Console.Write("Instance ");
}
}
class Test
{
static void Main()
{
new TestClass ();
Console.ReadLine ();
}
}
The output of the above program is 'Static Instance'. A
static constructor can only access static members of a class. The reason is
that at the time when a static constructor is loaded in the memory, the
instance members of a class are not available. In the following program, the
assignment to the non–static integer variable p inside the static constructor
is an error.
Listing 3: Static Constructor Can Access Only Static
Members
class Test
{
int p;
static Test()
{
p = 9;
}
public static void Main(string []args)
{
Test testObject = new Test();
/*Error: An object reference is required for the
non-static field, method,
or property 'Test.p'*/
}
}
Non-Static or Instance Constructors
Non-static constructors are also called instance
constructors, type constructors, or type initializers, and are used to create
and initialize instances of the class they belong to. We can have multiple
non-static constructors but only one static constructor for a class. A non-static constructor with no parameters is called the default constructor. If we
do not write any constructor for a class, the compiler automatically supplies
one. This is the implicit default constructor. This property of C# to supply an
implicit default constructor is revoked once we write any constructor for a
class.
Non-static constructors can be public, private, protected,
external, or internal. A public constructor is one that is called when the
class is instantiated. A private constructor is one that prevents the creation
of the object of the class. It is commonly used in classes that contain only
static members. A class containing an internal constructor cannot be
instantiated outside of the assembly. An internal constructor can be used to
limit concrete implementations of the abstract class to the assembly defining
the class. A protected constructor allows the base class to do its own
initialization when subtypes are created. When constructor declaration includes
an extern modifier, the constructor is said to be an external constructor. An
external constructor declaration provides no actual implementation and hence
does not contain any definition. It is to be noted that a public constructor
can access a private constructor of the same class through constructor
chaining.
Listing 4: Public Constructor Can Access Private Constructor
of the Same Class
using System;
class Test
{
public Test(): this(10)
{
Console.WriteLine("Default Constructor");
}
private Test(int intValue)
{
Console.WriteLine("Parameterized Constructor");
}
public static void Main(string []args)
{
Test testObject = new Test();
Console.ReadLine ();
}
}
The output is as follows:
Parameterized Constructor
Default Constructor
A protected constructor can only be invoked from the
subclasses of the class in which it is defined. This is illustrated in the
example that follows.
Listing 5
using system;
class B
{
protected B (string s) {}
}
class D : B
{
public D () : base ("Called from D class") {}
}
class E
{
public static void Main(string []args)
{
B x = new B ("Called from E class");
/*Error. The constructor test.B.B(string s) is inaccessible due to its
protection level*/
}
}
Constructor Overloading
A constructor can take zero or more arguments as parameters.
A constructor with zero arguments is known as the default constructor. We can
have multiple constructors in a class with different sets of signatures. Such
constructors are known as “overloaded constructors”. The overloaded
constructors of a class must differ in their number of arguments, type of
arguments, and/or order of arguments. This gives the user the ability to
initialize the object in multiple ways.
The class in the program shown below contains three
constructors. The first is the default constructor, followed by the two
argument constructors. Note that the constructors differ in their signature.
Listing 6: Overloaded Constructors
using system;
public class Test
{
public Test()
{
//Default constructor
}
public Test(int sampleValue)
{
// This is the constructor with one parameter.
}
public Test(int firstValue, int secondValue)
{
// This is the constructor with two parameters.
}
}
Constructor Chaining
Constructor chaining refers to the ability of a class to
call one constructor from another constructor. In order to call one constructor
from another, we use base (parameters) or : this (parameters) just before the
actual code for the constructor, depending on whether we want to call a constructor
in the base class or in the current class.
Listing 7: Constructor Chaining
using system;
public class Test
{
public Test(): this(10)
{
// This is the default constructor
}
public Test(int firstValue)
{
// This is the constructor with one parameter.
}
}
Constructors and Inheritance
A constructor of a base class is not inherited to its
derived class. However, a derived class constructor can call a base class
constructor, provided both are non-static.
Listing 8: Invoking a Base Constructor from the Derived
Class
using System;
class Base
{
public Base()
{
Console.WriteLine("Base Constructor Version 1");
}
public Base(int x)
{
Console.WriteLine("Base Constructor Version 2");
}
}
class Derived : Base
{
public Derived():base(10)
{
Console.WriteLine("Derived Constructor");
}
}
class MyClient
{
public static void Main()
{
Derived dObject = new Derived();
//Displays 'Base Constructor Version 2' followed by 'Derived Constructor'.
}
}
Constructors are executed in the order of inheritance as shown in the example below.
Listing 9: Order of Execution of Constructors in Inheritance
using System;
class Base
{
public Base()
{
Console.WriteLine("Base constructor");
}
}
class Derived : Base
{
public Derived()
{
Console.WriteLine("Derived constructor");
}
}
class Test
{
public static void Main()
{
Derived dObject = new Derived();
//Displays 'Base constructor' followed by 'Derived constructor'.
}
}
It is not possible to inherit a class that has only a private constructor.
Listing 10: Private Constructors Prevent Inheritance
using system;
class Base
{
Base( )
{
}
}
class Derived : Base // Syntax Error.
{
public static void Main()
{
Derived dObject = new Derived ();
}
}
Conclusion
The best practice is to always explicitly specify the
constructor, even if it is a public default constructor. Proper design of
constructors goes a long way in solving the challenges faced in class designs.