Intro to Object Orientated Programming Part 4 - Constructors

PlausiblyDamp

Administrator
Joined
Sep 4, 2002
Location
Lancashire, UK
Guide to Object Orientated code in .Net

This is a continuation of the series started in here and is preceded by this thread

Introduction
So far we have looked at creating a class that implements several OO concepts (Methods, properties, data hiding and overloading). In this article we will look at another feature – Constructors.

Constructors
One of the ideas behind OO code is that as much as possible we try to make code self contained and re-usable, one way to do this is to remove the need for people using our code to know how to initialise the internal data structures or require them to remember to call initialisation routines before using our code.

In it’s simplest form a Constructor allows our class to do it’s own initialisation before the object is available to any calling code.

The declaration of a constructor differs quite substantially between C# and VB.net. If we wished to perform some initialisation in our BankAccount class we could define a constructor as

Visual Basic:
Public Sub New()
_Balance = 0
        _AccountNumber = 0
End Sub

C#:
public BankAccount()
{
_Balance =0;
_AccountNumber =0;
}

As you can see in VB we simply declare a Subroutine called New, while C# uses the C++ style of constructor declaration which uses a method named the same as the class name. Notice that if we want to be able to create an instance of our class the constructors need to be publicly accessible. If we do not declare any constructor then the compile assumes we wanted one that does nothing and would act as if we had declared a constructor like
Visual Basic:
Public Sub New()
End Sub

C#:
public BankAccount()
{
}

If you add the code above to the BankAccount class from the previous article and step through in the debugger you will notice the constructor is automatically called when we create a new instance – there is no way to call it directly. You may also notice that currently it doesn’t really do anything worthwhile as we can already initialise the variables at the point of declaration anyway.
However there is one or two other things we can do with constructors to make them more useful.

Parameters
Just like normal methods constructors can also be passed parameters at run time. A better example than our simplistic one from above could be:
Visual Basic:
Public Sub New(ByVal accountNumber As Integer)
    _AccountNumber = accountNumber
End Sub
C#:
public BankAccount(int accountNumber)
{
_AccountNumber =accountNumber;
}

Allowing us to pass in a valid account number, note if you remove the previous constructor and use the one just above and attempt a recompile it will now fail! The reason being to create an instance we are now required to provide an account number. The auto generated constructor I mentioned above is only generated if we provide no constructors at all, if we provide a constructor that accepts parameters and still require a constructor that doesn’t we need to provide both.

To use the new constructor we need to change the way we create an instance of the class like so:
Visual Basic:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    AccA = New BankAccount(1)
    AccB = New BankAccount(2)
End Sub
C#:
private void Form1_Load(object sender, System.EventArgs e)
{
AccA = new BankAccount(1);
AccB = new BankAccount(2);
}
This now forces users of our class to provide an account number at the point of creation for the object.

Overloads
Like other class methods constructors can also be overloaded, for example we could chose to specify both an account number and an initial balance when we create a valid instance. Just like normal overloaded methods constructors can delegate part of the work to other versions, however yet again the syntax differs between VB and C#
Visual Basic:
Public Sub New(ByVal accountNumber As Integer, ByVal initialBalance As Decimal)
    Me.New(accountNumber)
    _Balance = initialBalance
End Sub
C#:
public BankAccount(int accountNumber)
{
_AccountNumber = accountNumber;
}

public BankAccount(int accountNumber, decimal initialBalance) : this(accountNumber)
{
_Balance = initialBalance;
}
Note how in C# we simply add : this(accountNumber) to the end of the new constructor while in VB we call the New method directly.
When we now create an instance of the BankAccount class we could use either the code provided above or alternatively provide a starting balance like:

Visual Basic:
AccA = New BankAccount(1, 1000)
AccB = New BankAccount(2, 500)
C#:
AccA = new BankAccount(1,1000m);
AccB = new BankAccount(2,500m);
Again you may find it worthwhile to step through the code in the debugger to get a feel for how the constructors are called in sequence.

ReadOnly variables
As we have seen previously we can prevent external modification of internal values by exposing read only properties such as Balance, now we have provided a value for _AccountNumber we may want to expose this value to other code in the same way.
Visual Basic:
Public ReadOnly Property AccountNumber() As Integer
    Get
        Return _AccountNumber
    End Get
End Property
C#:
public int AccountNumber
{
	get
	{
	return _AccountNumber;
	}
}
This style has served us well so far – we provide read only access to the balance and all modifications must go through our provided Credit and Debit methods, however the AccountNumber has an additional feature – namely we do not want the account number to change at all once the class has be instantiated. Not only should it be treated as read only to external code but it should never be modified by other methods in the class either. This can be achieved under .Net by marking the variable as readonly when we define it

Visual Basic:
Private ReadOnly _AccountNumber As Integer
C#:
private readonly int _AccountNumber =0;
this now results in a variable that can have a value provided at compile time and can be modified by a constructor, but no other code is allowed to alter the value at runtime; effectively the value we provide to the constructor is treated as read only once the constructor has exited and a valid instance of the class has been generated.

Shared / Static Constructors
Another thing to be aware of is that if our class contains shared (static in C#) data members that need initialising we can also provide a static constructor.
Visual Basic:
Shared Sub New()
	‘initialise shared data here
End Sub
C#:
public static BankAccount()
{
//initialise static data here
}

These cannot be parameterised nor do we have any control over when they are called – the framework will guarantee that they are called before the class is ever referenced but beyond that we have no control over when.

Preventing construction
A final thing to be aware of is that if you wish to prevent a class from ever being instantiated (e.g. System.Math or System.Windows.Forms.MessageBox) you can achieve this by creating a non-public default constructor and no publicly accessible ones.
Visual Basic:
Private Sub New()

End Sub
C#:
private BankAccount()
{

}
this can be useful if the class has no instance members or is never intended to be created from an external piece of code but by some internal mechanism.

Playtime
Again find attached a sample project containing working implementations of the above code. I suggest running the app and stepping through in a debugger to see how the constructors get called, you may want to alter the Form_Load and change the number of parameters being passed to see which Constructors get called.
As a final exercise you may want to modify (or add) a method other than a constructor and attempt to assign a new value to _AccountBalance to see what the compiler will report.

To Come
Next will will look at Inheritance
 

Attachments

  • BankVB.zip
    13.2 KB · Views: 24
  • BankCS.zip
    10.4 KB · Views: 17
Last edited:
Top Bottom