Search   Articles   Dev Forums   Personalize   Favorites   Member Login   ASP.Net Hosting
DevASP.NET for ASP.NET, VB.NET, XML and C# (C-Sharp) Developers Sunday, July 20, 2008

Search Directory
ASP.NET
VB.Net
C-Sharp
SQL Server
 

Constructor Methods


In VB.NET, classes can implement a special method that is always invoked as an object is created. This method is called the constructor, and it is always named New. We've seen this used before – most notably in a regular Windows form, where the New method is used to hold any initialization code for the form.


The constructor method is an ideal location for such initialization code, since it is always run before any other methods are ever invoked – and it is only ever run once for an object. Of course, we can create many objects based on a class – and the constructor method will be run for each object that is created.

 

The constructor method of a VB.NET class is similar to the Class_Initialize event in previous versions of Visual Basic, but is far more powerful in VB.NET since we can accept parameter values as input to the method.

 

We can implement a constructor in our classes as well – using it to initialize our objects as needed. This is as easy as implementing a Public method named New. Add the following to our Person class:

 

Public Sub New()

Phone("home") = "555-1234"

Phone("work") = "555-5678"

End Sub

 

In this example, we're simply using the constructor method to initialize the home and work phone numbers for any new Person object that is created.

Parameterized Constructors

We can also use constructors to allow parameters to be passed to our object as it is being created. This is done by simply adding parameters to the New method. For example, we can change the Person class as follows:

 

Public Sub New(ByVal Name As String, ByVal BirthDate As Date)

mstrName = Name

mdtBirthDate = BirthDate

 

Phone("home") = "555-1234"

Phone("work") = "555-5678"

End Sub

 

With this change, any time a Person object is created, we'll be provided with values for both the name and birth date. This changes how we can create a new Person object, however. Where we used to have code such as:

 

Dim myPerson As New Person()

 

Now we will have code such as:

 

Dim myPerson As New Person("Peter", "1/1/1960")

 

In fact, since our constructor expects these values, they are mandatory – any code wishing to create an instance of our Person class must provide these values. Fortunately, there are alternatives in the form of optional parameters and method overloading (which allows us to create multiple versions of the same method – each accepting a different parameter list – something we'll discuss later in the chapter).

Constructors with Optional Parameters

In many cases, we may want our constructor to accept parameter values for initializing new objects – but we also want to have the ability to create objects without providing those values. This is possible through method overloading, which we'll discuss later, or through the use of optional parameters.


Optional parameters on a constructor method follow the same rules as optional parameters for any other Sub routine – they must be the last parameters in the parameter list and we must provide default values for the optional parameters.

 

For instance, we can change our Person class as shown:

 

Public Sub New(Optional ByVal Name As String = "", _

Optional ByVal BirthDate As Date = #1/1/1900#)

mstrName = Name

mdtBirthDate = BirthDate

 

Phone("home") = "555-1234"

Phone("work") = "555-5678"

End Sub

 

Here we've changed both the Name and BirthDate parameters to be optional, and we are providing default values for both of them. Now we have the option of creating a new Person object with or without the parameter values:

 

Dim myPerson As New Person("Peter", "1/1/1960")

 

or

 

Dim myPerson As New Person()

 

If we don't provide the parameter values then the default values of an empty String and 1/1/1900 will be used and our code will work just fine.

Termination and Cleanup

In the .NET environment, an object is destroyed and the memory and resources it consumes are reclaimed when there are no references remaining for the object.

 

As we discussed earlier in the chapter, when we are using objects, our variables actually hold a reference or pointer to the object itself. If we have code such as:

 

Dim myPerson As New Person()

 

we know that the myPerson variable is just a reference to the Person object we created. If we also have code like this:

 

Dim anotherPerson As Person

anotherPerson = myPerson

 

we know that the anotherPerson variable is also a reference to the same object. This means that this specific Person object is being referenced by two variables.

 

When there are no variables left referencing an object, it can be terminated by the .NET runtime environment. In particular, it is terminated and reclaimed by a mechanism called garbage collection, which we'll discuss shortly.


 

Unlike COM (and thus VB6), the .NET runtime does not use reference counting to determine when an object should be terminated. Instead, it uses a scheme known as garbage collection to terminate objects. This means that, in VB.NET, we do not have deterministic finalization, so it is not possible to predict exactly when an object
will be destroyed.

Before we get to garbage collection, however, let's review how we can eliminate references to an object.

 

We can explicitly remove a reference by setting our variable equal to Nothing, with code such as:

 

myPerson = Nothing

 

There are two schools of thought as to whether we should still explicitly set variables to Nothing even when they fall out of scope. On one hand, we can save writing extra lines of code by allowing the variable to automatically be destroyed but, on the other hand, we can explicitly show our intent to destroy the object by setting it to Nothing manually.

Perhaps most important is the fact that the garbage collection mechanism will sometimes reclaim our objects in the middle of our processing. This can only happen if our code doesn't use the object later in the method. Setting the variable to Nothing at the end of the method will prevent the garbage collection mechanism from proactively reclaiming our objects.

 

We can also remove a reference to an object by changing the variable to reference a different object. Since a variable can only point to one object at a time, it follows naturally that changing a variable to point at another object must cause it to no longer point to the first one. This means we can have code such as:

 

myPerson = New Person()

 

which causes the variable to point to a brand new object – thus releasing this reference to the prior object.

 

These are examples of explicit dereferencing. VB.NET also provides facilities for implicit dereferencing of objects when a variable goes out of scope. For instance, if we have a variable declared within a method, when that method completes the variable will be automatically destroyed – thus dereferencing any object to which it may have pointed. In fact, any time a variable referencing an object goes out of scope, the reference to that object is automatically eliminated.

 

This is illustrated by the following code:

 

Private Sub DoSomething()

Dim myPerson As Person

 

myPerson = New Person()

End Sub

 

Even though we didn't explicitly set the value of myPerson to Nothing, we know that the myPerson variable will be destroyed when the method is complete since it will fall out of scope. This process implicitly removes the reference to the Person object created within the routine.


Of course, another scenario where objects become dereferenced is when the application itself completes and is terminated. At that point, all variables are destroyed and so, by definition, all object references go away as well.

 

We discussed garbage collection and the Finalize method in Chapter 3. When we discussed these concepts, we mentioned that there was no automatic way to perform the cleanup when the final reference to an object is released, although implementing the IDisposable interface provides one solution. We'll investigate that solution now.

The IDisposable Interface

In some cases the Finalize behavior is not acceptable. If we have an object that is using some expensive or limited resource – such as a database connection, a file handle, or a system lock – we might need to ensure that the resource is freed as soon as the object is no longer in use.

 

To accomplish this, we can implement a method to be called by the client code to force our object to clean up and release its resources. This is not a perfect solution, but it is workable. The thing to remember is that this method is not called automatically by the .NET runtime environment, but instead must be called directly by the code using the object.

 

The .NET framework provides the IDisposable interface that formalizes the declaration of this cleanup method. We'll discuss creating and working with multiple interfaces in detail later so, for now, we'll just focus on the implementation of the Dispose method from a cleanup perspective.

 

Any class that derives from System.ComponentModel.Component automatically gains the IDisposable interface. This includes all of the forms and controls that are used in a Windows Forms UI, as well as various other classes within the .NET framework. For most of our custom classes, however, we'll need to implement the interface ourselves.

 

We can implement it in our Person class by adding the following code to the top of the class:

 

Public Class Person

Implements IDisposable

 

This interface defines a single method – Dispose – that we need to implement in our class. It is implemented by adding the following code to the class:

 

Private Sub Dispose() Implements IDisposable.Dispose

colPhones = Nothing

End Sub

 

In this case, we're using this method to release our reference to the HashTable object that the colPhones variable points to. While not strictly necessary, this illustrates how our code can release other objects when the Dispose method is called.

 

It is up to our client code to call this method at the appropriate time to ensure that cleanup occurs. Typically, we'll want to call the method as soon as we're done using the object.


This is not always as easy as it might sound. In particular, an object may be referenced by more than one variable and just because we're dereferencing the object from one variable doesn't mean it has been dereferenced by all the other variables. If we call the Dispose method while other references remain – our object may become unusable and may cause errors when invoked via those other references. There is no easy solution to this problem – so careful design is required in the case that we choose to use the IDispose interface.

 

In our application's Form1 code, we use the OnLoad method of the form to create an instance of the Person object. In the form's OnClosed method, we may want to make sure to clean up by disposing of the Person object. To do this, add the following code to the form:

 

Private Sub Form1_Closed(ByVal sender As Object, _

ByVal e As System.EventArgs) Handles MyBase.Closed

 

CType(mobjPerson, IDisposable).Dispose()

 

End Sub

 

The OnClosed method runs as the form is being closed, and so it is an appropriate place to do
cleanup work.

 

Before we can dereference the Person object, however, we can now call its Dispose method. Since this method is part of a secondary interface (something we'll discuss more later), we need to use the CType() method to access that specific interface in order to call the method:

 

CType(mobjPerson(), IDisposable).Dispose()

 

CType() allows us to indicate the specific interface by which we want to access the object – in this case the IDisposable interface. Once we're using that interface, we can call the Dispose method to cause the object to do any cleanup before we release our reference:

 

mobjPerson() = Nothing

 

Once we've released the reference, we know that the garbage collection mechanism will eventually find and terminate the object – thus running its Finalize method. In the meantime, however, we've forced the object to do any cleanup immediately, so its resources are not consumed during the time between our release of the reference and the garbage collection terminating the object.



DevASP.Net - Disclaimer - Privacy
Copyright © 2008 DevASP.net