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)
{
//constructorbody
}
{
//constructorbody
}
As per the C# specification, a constructor can have the following modifiers.
public
protected
internal
private
extern
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 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.
A extern constructor is said to be an external constructor. An external constructor declaration provides no actual implementation and hence does not contain any definition.
Note: 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.
No comments:
Post a Comment