Using Constructors


There are a variety of ways in which we can design classes to use constructors both minimizing the amount of code that we write and maximizing the functionality and ease of implementation of our class. We can explicitly write a constructor as we have seen to initialize fields although whether we initialize their values (or not) in the constructor, the runtime will initialize the fields with default values prior to invoking the constructor. We will see in this section that if we don't write a constructor for a class, the compiler will create a default constructor and the runtime will invoke it when we create a new object.

Chaining Constructors

There are standard ways to write constructor code, which can be used to minimize the amount of code written, make the code more readable, and avoid replicating similar code blocks within the same class. Chaining constructors is an effective way to build a very advanced interface with multiple overloaded constructors while providing and using an implementation for a single constructor.

The Manager class detailed shortly is a typical implementation of a class that uses constructor chaining to call one constructor from another. There are three Manager constructors; the last one contains two parameters and is the only constructor with an implementation. The first thing that each of the other constructors will do is to call the third constructor. This is done by using the this self-referential pointer to the current object. This syntax is new to C#; however C++, Jscript, and Java developers should be familiar with the use of this. The call to the two-parameter constructor will occur and it will populate the fields with the defaults specified and then any implementation code within the constructor code blocks will be invoked. There is extra code in the default parameter-less constructor so that we can ensure that it is logged every time we create a Manager class without a name (the entry is added to the event log). The file shown below is called chaining_const.cs:

     using System;     public class Manager     {       private int grade;       private string name;       public int Grade       {         get { return grade; }         set { grade = value; }       }       public string Name       {         get { return name; }         set{ name = value; }       }       public Manager() : this("N/A", 0)       {         Console.WriteLine("Manager created without name!");       }       public Manager(string name) : this(name, 0) {}       public Manager(string name, int grade)       {         Name = name;         Grade = grade;       }       public override string ToString()       {         return "Name: " + this.Name + ", Grade: " + this.Grade.ToString();       }     } 

Including the following Main() method will call the constructor with one parameter and passing the name Jones and a default grade of 0 to the implementation constructor.

     public static void Main()     {       Manager mgr_Jones = new Manager("Jones");       Manager mgr_Blank = new Manager();       Manager mgr_Name_Grade = new Manager("Jones", 4);       Console.WriteLine(mgr_Jones.ToString());       Console.WriteLine(mgr_Blank.ToString());       Console.WriteLine(mgr_Name_Grade.ToString());     } 

Calling a Base Class Constructor

Every deriving class invokes the base class constructor either implicitly or explicitly. In fact if we don't call the base class constructor the CLR will call it for us (the CLR will call the parameter-less constructor). The base class constructor can be called only from the derived class's constructor and it is the first thing that will be called followed by any implementation code within the derived class's constructor code block.

We could add two constructors to the abstract BasicShape class created earlier, marking them protected so that only a derived class can call them. We could also mark them public and it would make little difference, as the base class cannot be instantiated as it is abstract.

     public abstract class BasicShape : IDisposable     {       protected BasicShape()       {         x = 1;         y = 1;       }       protected BasicShape(int x, int y)       {         this.x = x;         this.y = y;       }       ... 

In the derived class we can now add some code, which will call the base class's constructors. Each one of these methods calls the base class constructor as shown using the base keyword preceded by the colon. This constructor will be invoked before invocation of the derived class constructor occurs. As in the example below we don't always have to invoke a constructor on the base class with the same signature as a constructor on the derived class. We can see from the example that the Square() constructor with no arguments will invoke the base class constructor with two arguments.

     public Square() : base(4, 4)     {       this.a = 1;       this.b = 1;     }     public Square(int a, int b) : base(4, 4)     {       this.a = a;       this.b = b;     } 

Private Constructors

Private constructors at first seem purposeless, but they are in fact quite prolific within the .NET Framework classes. Generally, they are used within classes that contain many static methods that are supposed to be used as a library rather than an object; the constructor is added to ensure that the class cannot be created by anything external to it.

There are two reasons that are apparent for creating private constructors. There may be occasions when the class creation code should be prevented from using a public constructor. One case would be where it doesn't make sense to create an object without providing some initialization parameters, such as with a FileStream class.

The second reason is with creating certain object design patterns, like the factory pattern where a public static method on the class will call the private constructor and return an instance of the object to the object creation code, or the Singleton pattern, where the constructor should only be called once. We will delve into this later in the chapter.

In the example overleaf, the Teacher class is created using a public constructor and it throws an exception if a grade of less than 3 is passed to that constructor. Rather than using inline code or another method, it uses a private constructor to raise the exception. This example is greatly simplified, as in reality the private constructor would contain extra initialization code. In this example, any external code cannot create an instance of the Teacher class using a parameter-less constructor.

     using System;     public class Teacher     {       int grade = 0;       public Teacher(int grade)       {         if(grade < 3)           new Teacher();         else           throw new ArgumentException("Grade must be less than 3");         this.grade= grade;       }       private Teacher()       {         // Initialization code       }     }     public class TestTeacher     {       static void Main()       {         Teacher teach = new Teacher(3)       }     } 

Earlier we saw that the derived class always calls the base class constructor whether specified or not. This effectively signifies that classes with private constructors cannot act as base classes as their constructor is not visible to the derived class.

There is one situation where the class containing the private constructor can be created by something other than itself. This occurs when another class is nested in the class with the private constructor. The nested constructor can always create an instance of its container class, whether the constructor is private or not.

The following NestedWorker class is nested within the Worker class. The former class has a public constructor and the latter a private constructor, to which the Worker class will create a reference and store it locally. We can therefore create and invoke the public constructor of the container class Worker from the nested class NestedWorker as shown in the Main()method, in the code below called nested_const.cs:

     using System;     public class Worker     {       public class NestedWorker       {         Worker wk;         public NestedWorker()         {           wk = new Worker();         }       }       private Worker()       {         Console.WriteLine("private constructor called!");       }       static void Main(string[] args)       {         NestedWorker nw = new NestedWorker();       }     } 

Static Constructors

Static constructors can be used in C# to initialize class data in the same way that instance constructors are used to initialize instance data. There are some differences in the rules governing static constructor use compared to instance constructor use. Unlike instance constructors they cannot be overloaded and so the only available static constructor is the default parameter-less constructor. Static constructors also cannot be invoked explicitly, and will not be inherited in a derived class, although they will be invoked when the base class type is created.

There are several guarantees made by .NET regarding the use of static constructors:

  • They are invoked before a single instance of the class is created and hence before any instance constructors.

  • They are invoked only once before the first instance of a class is created

  • The static constructor is called before any static fields are referenced

To check the calling order of static constructors and instance constructors, we can add a static constructor and a public instance constructor to the Teacher class that was created in the previous example. We use the static keyword to define the static constructor and differentiate it from the instance constructors. This static constructor will allow us to initialize all the static members in the class. Java has an equivalent principle of static constructors, which are declared without referencing the class name as in C#, so a static constructor declaration is generally the word static followed by a code block. The following example is called static_const.cs:

     ...     public class Teacher     {       public Teacher()       {         Console.WriteLine("Base class instance created");       }       static Teacher()       {         Console.WriteLine("Class loaded");       }       ... 

Then we create the SupplyTeacher class that derives from the Teacher class. This will result in the static constructor being invoked first before the base class instance constructor is invoked.

     public class SupplyTeacher : Teacher     {       public SupplyTeacher ()       {         Console.WriteLine("Derived class instance created");       }     }     public class TestStaticConstructor     {       static void Main(string[] args)       {         SupplyTeacher teach = new SupplyTeacher();         SupplyTeacher teach1 = new SupplyTeacher();       }     } 

When an instance of the SupplyTeacher class is created the following output occurs confirming the order of invocation of each constructor type. In this example, two SupplyTeacher objects are created to demonstrate that the static constructor will only be invoked once even though the base class instance constructor is invoked twice with identical object creation patterns.

     C:\Class Design\Ch 05>static_const     Class loaded     Base class instance created     Derived class instance created     Base class instance created     Derived class instance created 




C# Class Design Handbook(c) Coding Effective Classes
C# Class Design Handbook: Coding Effective Classes
ISBN: 1590592573
EAN: 2147483647
Year: N/A
Pages: 90

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net