Construction And Disposal


This final section of the appendix leaves inheritance behind and looks 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 is 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 you could do the same for your own classes? Well, most modern OOP languages 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 is 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.

That said, 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 in C# than in C++!). For that reason this appendix won't look any more closely at destructors. How to write destructors in C# is covered in Chapter 5, "Operators and Casts." This appendix concentrates on constructors, to give you an idea of how the concept works.

Note

Visual Basic 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 you have a class named MyClass, a skeleton constructor will be defined as follows:

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

This constructor so far does nothing, because you haven't added any code to it. Add an integer field MyField to the class and initialize it to 10:

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

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 previous example, you might wonder if you've actually achieved anything new. After all, in terms of C# syntax, you could have written:

public class MyClass private int myField = 10;  

This achieves the same effect — specifying how to initialize each object without explicitly indicating a constructor. Indeed, you have already done something like this in all the Authenticator samples, in which you specified that the password field should automatically be initialized to an empty string. The answer is that here we are trying to introduce the concept of a constructor. The preceding code is really just C# shorthand for specifying construction code implicitly — a shorthand that is specific to C#. Behind this shorthand there is still a constructor at work. Besides, by writing a constructor explicitly, it means you 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 — you haven't supplied one for any of the examples so far. In general, if you don't explicitly supply any constructor, the compiler will just make up a default one 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 bools).

Note

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 might differ. 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, its members won't get initialized to anything (unless they have constructors instead).

Passing parameters to constructors

Let's go back to the Authenticator class. Say you wanted to modify the class so that you can specify the initial password when you 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 you can define whatever parameters you want for it, and this is where constructors really score over Visual Basic's Initialize or Form_Load.

For the Authenticator, you'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 you initialized it by calling a method after instantiating an object.

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

 Authenticator NewUser = new Authenticator("MyPassword45"); 

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

 Authenticator NewUser2 = new Authenticator(); 

This is because you do not supply any parameters to the constructor, and the constructor requires one parameter. However, if you wanted to, you 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 you'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 want 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 you wanted to do that for the Authenticator class, you 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 might not have many practical applications, but it demonstrates the kind of flexibility you have by being able to specify your own constructors. Counting instances is 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# 2005
Pro Visual C++ 2005 for C# Developers
ISBN: 1590596080
EAN: 2147483647
Year: 2005
Pages: 351
Authors: Dean C. Wills

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