Construction and Disposal

 
Appendix A - Principles of Object-Oriented Programming
bySimon Robinsonet al.
Wrox Press 2002
  

For this final section of the appendix, we are going to leave inheritance behind, and look at another topic that is important in OOP programming: creation and disposal of objects or to use the usual terminology construction and destruction of objects. Say you have this code:

   {     int x;     // more code     }   

You will be aware that when x is created (comes into scope), memory gets allocated for it, and that when it goes out of scope, that memory is reclaimed by the system. If you are familiar with C#, you'll also be aware that x gets initialized with the value zero when the variable comes into scope. For integers, the language defines what initializations happen automatically when an int gets created. But wouldn't it be nice if we could do the same for our own classes? Well, most modern OOP languages will support the ability to do this and C# is no exception. This support happens through something called a constructor . A constructor is a special method called automatically whenever an object of a given class gets created. You don't have to write a constructor for a class, but if you want some custom initialization to take place automatically, you should place the relevant code in the constructor.

Similarly, OOP languages, including C#, support something called a destructor . A destructor is a method called automatically whenever an object is destroyed (the variable goes out of scope). Reclaiming memory aside, destructors are particularly useful for classes that represent a connection to a database, or an open file, or those that have methods to read from and write to the database/file. In that case, the destructor can be used to make sure that you don't leave any database connections or file handles hanging open when the object goes out of scope.

Having said all that, the facilities offered by the .NET Framework and the garbage collector mean that destructors are not only used a lot less often in C# than they are in pre-.NET languages, but also that the syntax for defining them is more complex (indeed, destructors are almost the only thing that is more complex to code up in C# than in C++!). For that reason we won't look any more closely at destructors in this appendix. How to write destructors in C# is covered in Chapter 3. Here, we will concentrate on constructors, to give you an idea of how the concept works.

VB developers will note that there are some similarities between constructors and the Initialize() and Form_Load() methods of VB class modules. Constructors, however, are far more flexible and powerful.

Creating Constructors

When you see a constructor definition in C#, it looks much like a method definition, but the difference is that you don't usually call a constructor explicitly. It's like a method that is always called on your behalf whenever an instance of a class is created. In addition, because you never call the method explicitly, there is no way you can get access to any return value, which means that constructors never return anything. You can identify a constructor in a class definition because it always has the same name as the class itself. For example, if we have a class named MyClass , a skeleton constructor would be defined as follows :

   public class MyClass     {     public MyClass()     {     }     ...   

This constructor so far does nothing we haven't added any code to it. Let's add an integer field MyField to the class and initialize it to 10:

 public class MyClass    {       public MyClass()       {   myField = 10;   }   private int myField;   ... 

It's as simple as that. Notice that no return type is specified, not even void . The compiler recognizes the constructor from the fact that it has the same name as the containing class. You should note that one implication of this is that it is not possible to write a method that has the same name as the class it belongs to, because if you do the compiler will interpret it as a constructor.

From the above code, you may wonder if we've actually achieved anything new. After all, in terms of C# syntax, we could equally have written

 public class MyClass   private int myField = 10;   

which achieves the same effect specifying how to initialize each object without explicitly indicating a constructor. Indeed, we have already done something like this in all our Authenticator samples, in which we specified that the password field should automatically be initialized to an empty string. The answer is really that here we are trying to introduce the concept of a constructor. The above code is really just C# shorthand for specifying construction code implicitly and is a shorthand that is specific to C#. Behind the shorthand there is still a constructor at work. Besides, by writing a constructor explicitly, it means we can write code to compute initial values at runtime the shorthand requires values to be known at compile-time, as constants.

It's not necessary to provide a constructor for your class we haven't supplied one for any of our examples so far. In general, if you don't explicitly supply any constructor, the compiler will just make a default one up for you behind the scenes. It'll be a very basic constructor that just initializes all the member fields to their normal default values (empty string for strings, zero for numeric data types, and false for bool s).

Initializing to default values is something that happens in C# because C# initializes all members of a class. If you are coding in a different language, this behavior may be different. For example, by default C++ never initializes anything unless you explicitly indicate that's what you want. So in C++, if you don't supply a constructor to a class, then its members won't get initialized to anything (unless they have constructors instead).

Passing Parameters to Constructors

Let's go back to our Authenticator class. Say we wanted to modify the class so that we can specify the initial password when we first instantiate the class. It is possible to do this by supplying a constructor that takes parameters. In this regard, a constructor behaves like a method in that we can define whatever parameters we want for it, and this is where constructors really score over VB's Initialize or Form_Load .

For the Authenticator , we'd probably add a constructor that takes an initial password as a parameter:

 public class Authenticator    {   public Authenticator(string initialPassword)     {     password = initialPassword;     }   private string password = "";       private static uint minPasswordLength = 6;       ... 

The advantage of using such a constructor is that it means an Authenticator object is guaranteed to be initialized the instant it is created. It is, therefore, not possible for other code to access the object before it has been initialized, as would be possible if we initialized it by calling a method after instantiating an object.

Now, to instantiate the object we would use a line of code similar to the following:

   Authenticator NewUser = new Authenticator("MyPassword45");   

Here we have created an instance with the password MyPassword45 . You should note that the following line will not compile any more:

   Authenticator NewUser2 = new Authenticator();   

This is because we do not supply any parameters to the constructor, and constructor requires one parameter. However, if we wanted to, we could simply create an overload for the constructor that didn't take any parameter arguments, and simply set a default password in this constructor overload (this would not be a very secure approach though!).

More Uses of Constructors

Although the only thing we've done with constructors is to initialize the values of fields, a constructor does act as a normal method so you can place any instructions you wish in it for example, you might perform some calculations to work out the initial values of the fields. If your class encapsulates access to a file or database, the constructor might attempt to open the file. The only thing that you cannot do in a constructor is return any value (such as indicating status) to the calling code.

Another novel use is to use a constructor to count how many instances of a class have been created while the program is running. If we wanted to do that for the Authenticator class, we could create a static field, nInstancesCreated , and amend the code for the constructor as follows:

 public class Authenticator    {   private static uint nInstancesCreated = 0;   public Authenticator(string initialPassword)       {   ++nInstancesCreated;   Password = initialPassword;       }       private string password = 10;       private static uint minPasswordLength = 6;       ... 

This example is here more to demonstrate the kind of flexibility that being able to specify your own constructors gives you than because it's likely to have much practical benefit. Counting instances is, it should be said, something you're unlikely to want to do in release builds of code, but it's something that you might want to do for debugging purposes.

  


Professional C#. 2nd Edition
Performance Consulting: A Practical Guide for HR and Learning Professionals
ISBN: 1576754359
EAN: 2147483647
Year: 2002
Pages: 244

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