Advertisment

Exception Handling in C#

author-image
PCQ Bureau
New Update

No one is perfect. And that holds true for even the best programmer. So, while one strives to write the most syntactically correct code, there are situations, especially during runtime, when certain errors are encountered. Most languages provide a means for handling such runtime error conditions, named exceptions, which are usually unpredictable. An infamous example is the “This program has performed an illegal operation” dialog box, which Windows 9x throws up when a runtime exception occurs. This is an example where even the author of the software cannot predict why and how the fault is happening.



This article will introduce you to C#’s exception-handling capabilities. The concept of exceptions remains the same as in C++, but some obvious specifics are involved.

Advertisment

Exception handling: The why

Most languages provide some facility to indicate error conditions. A popular methodology is to return a value from a function to indicate an error as below:

bool my_func()



{


….


if (some_variable <= -1)


return false;


else


return true;


}





Advertisment

The methodology of handling errors requires some work on the part of the author.

The author may not accept the return value, by writing code like this:

….



my_func();


…. // continue working
Advertisment

Even if the author accepts the return value, he may not use it to take appropriate program flow path as shown value:

….



bool retval=my_func();


int a=2;


….. // continue working… don’t use the return value of my_func

The concept of exceptions eliminates both these problems because they can’t be ignored. If ignored, the software will terminate execution.You can handle exceptions at any level, and not necessarily at the level where they are thrown. What this means is that, taking the above example, while the value of retval must be used at the point where it is returned, and cannot be used to make a decision in the caller of the function that called my_func, it is possible to handle the exception in the caller function of the function that called

my_func.

Advertisment

Exception handling: Throw and catch

In C#, an error condition is indicated by using the throw statement that is used to throw an exception, that is, indicate an error as shown below:

void my_func()



{


if (some_variable <= -1)


throw new System.Exception();


// code here and below is never executed when an exception is thrown.


}



Advertisment

When indicating exception conditions, we usually throw an object that indicates the type of error that has occurred. C# mandates that the object should either be a System.Exception object or some object derived from the same. Hence, in the snippet above, an object of the type of System.Exception has been created and thrown. We cannot throw an exception of any type as is possible under C++.

Once an exception has been thrown, the runtime checks the current method (which happens to be the one which threw the exception) for exception-handler code. If found, control is transferred to it. If it isn’t found, then the runtime goes up the stack to the method which called the method that threw the exception. If a handler is found there, control is transferred to it. But if a handler isn’t thrown there, the runtime goes further up the stack, till the Main function, until it encounters a handler. If one is found at any level, control is transferred to it at that level. If even Main doesn’t handle the exception, then the runtime displays a dialog box, as shown below, and terminates program execution.

Let’s now move onto handling exceptions. Technically, the handling of exceptions is referred to as catching an exception. Once an exception is thrown, it is caught. Exceptions are usually handled using pairs of try-catch blocks. Code that is likely to produce an exception is enclosed between a try block and the corresponding code that is likely to catch the exception is enclosed between a catch block as shown below:

Advertisment
int some_variable=-2;



try


{


if (some_variable <= -1)


throw new System.Exception();


// control never comes here


some_variable=3;


}


catch(System.Exception oe)


{


Console.WriteLine(“Exception caught”);


}


// code here is executed


some_variable=5;











After initializing the variable to —2, when the code enters the try block, an exception is thrown. The point to be noted is that if an exception is thrown, any statements after the one, which threw the exception, are ignored and not executed by the runtime. Instead, the runtime starts to look for an appropriate exception handler catch block. A catch block that has the same exception object as the one thrown is the preferred catch block for handling the exception. In the above example, a corresponding block is found and control gets transferred there, where the user is told about the catching of the exception. Then, the code outside the catch block executes. The catch block is only executed when an exception is thrown. Had the variable been initialized to 3, the exception would have never executed and hence, the catch block would have never been executed. The execution would have proceeded normally.

The correct ordering of the catch block is essential for correctly catching the exceptions. Suppose, we derive a custom exception object from System.Exception, and then throw a custom exception object, the catch handlers would have to be coded as shown below:

Advertisment
catch(MyCustomException mce)



{


// catches any exceptions of the custom exception object


}


catch(System.Exception ge)


{


// catch an exception object of the type System.Exception


}





This is because, had the System.Exception catch clause been put earlier, then it would have caught the custom exception since all the custom exceptions are derived from System.Exception. If you aren’t sure what kind of exception the code might have to handle, you may omit the exception object type from the catch clause as shown

below.

catch



{


// handles all kinds of exceptions


}

Another block which is associated with the try block is the finally block that is executed before the execution of the try block completes, but upon the completion of execution of the catch block. The code in the finally block shall execute irrespective of whether the code in the the code in the try block executed normally or throws an exception:

try



{


// some code comes here which may or may not throw an exception


}


catch(System.Exception oe)


{


// if an exception is thrown, catch it..


}


finally


{


// handle any kind of cleanup that is required.


}









C# provides a number of exceptions, all of which are derived from System.Exception base class. For eg. AccessException when there is failure to access a method or field of a class, ArgumentOutOfRangeException when argument value goes out of range, etc. Refer to the .NET reference for a list of the exceptions supported.

The accompanying CD carries a program, which shall throw an exception if no argument is specified in the command line. It shall not only show the working of a try-catch-finally structure, but will also show how to accept argument from the command line.

Understanding Classes





With the advent of object-oriented programming (OOP), the concepts of classes have become the center of programming. All program designs revolve around the concept of classes, which help us represent the entities in real-life problems, as closely as possible in a programming language’s syntax. In this regard, C# is no different from any other OO language, and supports the concept of classes. In fact, like others in its category, a C# program cannot work without a class definition, one of which must contain the implementation of the Main method, from where program execution commences. This article explains the various class-related concepts in C#.

What’s OOP?

Before we get into the details, memorize this for good: OOP is not any kind of new language. Rather, it’s a way of programming, a way of writing code so that it becomes more efficient in terms of usage, reusability, testing, and the like. A given problem may be tackled using the procedural way of programming or the OO programming way. Discussing in detail the merits and demerits of the two approaches is beyond the scope of this article, more so because it has been dealt rather well by many other authors. If you are new to OOP fundamentals, especially if you are switching to OOP from procedural programming (as is done in C), we strongly suggest that you first develop a way of thinking in terms of OOP, which is thinking in terms of objects. This way of thinking can happen only with time and can’t be learnt overnight and, hence, will take time. So be patient… that’s the only way. For an overview of OOP, refer to our July 2001 issue.

Classes and objects

In C#, a class is defined using the class key word:

class CMyFirstClass



{


public int v1;


public void m1()


{


Console.WriteLine(“V1 = {0}”,v1);


};


}





The class keyword is followed by the name of the class. The name is used to instantiate the class to create its objects. Each class has some kind of data associated with it that is stored in variables belonging to the class. These variables in C# are termed as fields. Likewise, there are certain functions belonging to the class that work upon the data contained in the class’s fields. These functions are termed as methods. So, in the example above, v1 is a field while m1 is a method. Another important point to be noted is that, unlike C++ but like Java, the class’s implementation is contained within the class definition. Now, to instantiate a class, we have to create its object, which is done as shown below:

CMyFirstClass mfcobj = new CMyFirstClass();

What this statement means is that we create a new instance of the CMyFirstClass class and let the mfcobj variable be a reference to it (recall that classes are reference types). So, it access a field or a method, we use the dot notation with the variable referencing the instance of the class:

mfcobj.v1=2; // assign the field v1 a value of 2



mfcobj.m1(); // call the method m1 to display the value of v1

There are few methods that are special in context of class instantiation. These methods have the same name as that of the class, they don’t return any value and are conventionally used to initialize the fields of the class before any methods are called. These methods are called constructors and are called automatically during the class instantiation process:

class CMyFirstClass



{


int v1;


public CMyFirstClass()


{


v1=0; 


}


public CMyFirstClass(int v1)


{


this.v1=v1;


}


public void m1()


{


Console.WriteLine(“V1 = {0}”,v1);


}


public ~CMyFirstClass


{


// perform cleanup of re sources


}


}

















When we create an object of the above class using the new operator, as done earlier in the article, the constructor that doesn’t take any parameters is called. Such a constructor is termed as a default constructor, and in the above example, it initializes the field v1 to the hardcoded value of zero. But what if we wish to initialize a field with a value of our own choice? In this case, the object is created as shown below:

CMyFirstClass mfcobj = new CMyFirstClass(10);

In this case, that constructor of the class is called which takes an integer as its parameter. Any constructor that takes one or more parameters is termed as a parameterized constructor. In the discussed example, when the constructor is called, it initializes the value of field v1 as:

this.v1 = v1;

Note that each class method is called, or a class field is referenced, in context of a given object. Thus, if mfcobj1 and mfcobj2 are two objects of CMyFirstClass, then the value of v1 in both the cases is going to be located in different memory locations. The compiler must know which object are you referring to when you call a given class method or refer to a class field. This is accomplished using the this pointer, which points to the object in whose context the operation is occurring. The use of this pointer is required in the above example since the field name and the parameter name for the constructor are the same. Had they been different, we wouldn’t have to use the this pointer; the compiler would have used it automatically.

Now, let’s see what happens when the object variable goes out of scope, i.e., when it dies away. When this happens, a special class method, which has the same name as the class but with a tilde (~) prefixed to it, is called. This method is called a destructor, and it serves the responsibility of releasing any used resources. This seems to be pretty much similar to what is present in C++. But then, that’s where the similarity ends. While in C++ it was for sure that the destructor would be called whenever the object would go out of scope, this isn’t necessary in C#. This is so because C# utilizes what is called the garbage collector, which is executes on an independent thread and has the responsibility of releasing the memory utilized by objects. The problem is that under normal circumstances, its C#, and not you, who controls when garbage collector comes to life and reclaims the used memory. Moreover, the order in which the destructors are called is also not certain; another deflection from the conventional C++ behavior. This process of reclaiming the memory used by objects that have gone out of scope is termed as finalization. So, that’s all there is to understanding object lifetime: how objects are created, what happens when they are created, and what can be called when the objects go out of scope. 

Const or Read-only?

In C#, one may use the const modifier to tell the compiler that the given member field is the class’s constant member:

public const string my_name = “Gaurav”;

The hitch is that you should know at compile time what value the field should be carrying. But what if you don’t know the value? In that case, C# provides you with the readonly modifier that lets you set the value of the field in the constructor, and once it is set, it cannot be changed, and thus, is read only in nature:

class Cbase



{


public readonly string name;


Cbase(string pname)


{


name=pname;


}


}





The constructor is passed the value to be assigned to the readonly field, which is then set in the constructor. Thus, one gets the flexibility of assigning the value of a field that is expected to be constant, i.e. read only, for its entire lifetime.

Then, there are also certain class members that belong to the class as a whole, and not any particular object instantiation. Such members are called the static members. Till this point, we have used the class member using the . notation, where was an object of the particular class. Static members on the other hand, as also explained in the July article, use the . notation. So, if there were a class declaration like the following:

class Cbase



{


public static int v1;


public static void m1()


{


Console.WriteLine(“Static V1 = {0}”,v1);


}


}





then the static members would be used as:

Cbase.v1=10; // assign the static field a value



Cbase.m1(); // display that value

That’s all there is for now. Next month, we’ll talk in detail about the methods, their parameters and more.

Kumar Gaurav Khanna runs www.wintools.f2s.com

Advertisment