06 Aug, 2007 · 7 minutes read
A class contains data members (variables) and member functions. Initializing the values of these data members is essential, at times. Take a look at the following scenarios:-
int MyNumber;
Console.WriteLine("My Number = {0}", MyNumber);
This block of code declares a variable MyNumberand then prints it on the screen. However, when you try to execute these instructions, an error Use of unassigned local variable ‘Product’will be generated. This is because, we are trying to use the value of MyNumber, even before we have assigned it one. This is where initialization comes in. Many languages do implicit initialization based on the type of these atomic (int, char, bool, string, etc) data types. Example: 0for int, falsefor bool, “” or NULL string for string. But, a strongly typed language like C# doesn’t. The corrected code would be as follows:-
int MyNumber = 10;
Console.WriteLine("My Number = {0}", MyNumber);
Take a look at this code snippet.
int Product;
for (int I = 1; I <= 10; I++)
{
Product *= I;
}
Console.WriteLine("The product of the first 10 natural numbers is {0}", Product);
This block of code is meant to calculate the product of the first 10 natural numbers. For this, we have setup a loop running from 1 to 10 and declared a variable named Productto store the running product. Finally, we display the result using Console.WriteLine. Again, this block of code generates an error on line 4. This is because, we haven't initialized the value of Product. The expression Product *= Iis equivalent to Product = Product * I. When this expression is being evaluated for the first time, the Right Hand Side (RHS) part will be evaluated first. This generates the error because at the moment, Producthas no value.
In the previous versions of VB (not VB .NET), the value for Productwould have been automatically set to 0. While, this would take care of this error, a logical error would creep in and drive the calculations crazy - the product of first 10 natural numbers = 0. To correct this, Productmust be initialized to 1. In situations like these, an initialization is a must. Here's the corrected code:-
int Product = 1;
for (int I = 1; I <= 10; I++)
{
Product *= I;
}
Console.WriteLine("The product of the first 10 natural numbers is {0}", Product);
Data members can be initialized in a similar fashion:-
class MyClass
{
int MyNumber = 69;
}
However, its a better approach to have a method do all initializations inside a class.
class MyClass
{
int MyNumber;
public void Initialize()
{
MyNumber = 69;
}
}
After instantiating the object of this class, the method Initializewould have to be called to set the initial value for MyNumber.
MyClass ClassA = new MyClass();
ClassA.Initialize();
This approach has a disadvantage too. The Initialize method needs to be called explicitly following the object instantiation. This is where the constructor jumps in. To define it: A Constructor is a special method which bears the same name as that of the class it is in and is used for initializing the data members of the class. Summing up the important properties of the constructor:-
Here is how the previous example would look when done with constructors.
class MyClass
{
int MyNumber;
public MyClass()
{
MyNumber = 69;
}
}
Now, when the class is instantiated, the method MyClass() will be automatically invoked and MyNumber will be assigned the value 69.
Constructors can either be associated with a class's instance (object) or the class itself. Instance constructors are the ones associated with the object and are invoked when an object of the class is instantiated. They can be used to initialize the non static members of the class. The above example was that of an instance constructor.
Static constructors on the other hand, are invoked only once during the execution of the program and can be used to initialize the static variables.
Example:-
public class MyClass
{
static int MyNumber;
static MyClass()
{
MyNumber = 69;
}
}
A class can have these two constructors existing simultaneously:-
public class MyClass
{
static int MyNumber;
int YourNumber;
static MyClass()
{
MyNumber = 69;
}
MyClass()
{
YourNumber = 69;
}
}
Note: Static constructors can't be used to initialize non-static variables and Instance constructors can't be used to initialize static variables.
public class MyClass
{
static int MyNumber;
int YourNumber;
static MyClass()
{
YourNumber = 69; // Error: YourNumber is not a static member
}
MyClass()
{
MyNumber = 69; // Error: MyNumber is a static member
}
}
The instance constructors we have seen up until this point are all default constructors. They initialize the variables with hard-coded values and are hence not flexible. We can use parameterized constructors to overcome this problem. Parameterized constructors as the name suggests, take parameters with which they initialize the values of the member variables.
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
MyClass ClassA = new MyClass(69);
}
}
public class MyClass
{
int MyNumber;
public MyClass(int Number)
{
this.MyNumber = Number;
}
}
}
Multiple, parameters can be supplied by separating each of them with a comma. The thiskeyword can be used to get a reference to the current instance of a class.
That which can be created, can be destroyed. Hence came the destructor which has the same name as that of the class it is in and is prefixed by a tilde (~) symbol. Destructors are automatically invoked when the instance of the class is destroyed. They are ideally used to release any memory occupied by the member objects. The .NET Framework automatically manages the memory for the atomic data types (int, string, char, etc). However, user defined data types are managed using a safe mechanism which does not release the memory occupied by an object unless all references to it are destroyed. This can be done in the class destructor. The following example, instantiates an object of the Socket class (located in the System.Net.Sockets namespace) inside the constructor and closes it inside the destructor.
class MyClass
{
System.Net.Sockets.Socket Sck;
MyClass()
{
Sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
~MyClass()
{
Sck.Close();
}
}
The .NET Framework isolates the programmers from having to handle memory requirements. Garbage collection is the process of releasing the memory occupied by unused objects. Unlike, C++ there is no delete keyword in C# and objects cannot be explicitly destroyed. This job is automatically carried out by a special program of the .NET Framework known as the Garbage collector(GC). This program periodically scans the application for objects with no references and marks them for deletion. It is the GC which determines when the destructor of an object is invoked. This way, the GC ensures that only unused objects get destroyed.
This method allows an Object to attempt to free resources and perform other cleanup operations before the Object is reclaimed by garbage collection.
Source: MSDN
This method is invoked when all of the references to an object are released from the memory. It does nothing by default and needs to be overridden. However, the precise timing of when the Finalize method would be invoked cannot be predicted. The CLR utilizes a system called reference-tracing Garbage collection, where by the GC periodically looks for objects that have no references left. Once such an object is found, the CLR invokes the Finalize method for the object, following which, the memory occupied by the object is released.
All classes that implement the IDisposable interface must define the Dispose() method. This method is to be used to perform application-defined tasks associated with freeing, releasing, or resetting unmanaged resources like Database connections, etc. Unlike, the Finalize() method, the Dispose() method is not automatically called and it must be explicitly called when the object is no longer in needed.
Fore more information on the Garbage Collection process, read this articlewritten by Jeffrey Richter.