Friday, 13 January 2012

Private Assemblies | VB.Net Tutorial For Biginners PDF Download

    A private assembly is an assembly that is deployed with an application and is available only for that application. That is, other applications do not share the private assembly. Private assemblies are installed in a folder of the application's directory structure. Typically, this is the folder containing the application's executable file.
   For most .NET Framework applications, you keep the assemblies that make up an application in the application's directory, in a subdirectory of the application's directory. You can override where the CLR looks for an assembly by using the <codeBase> element in a configuration file.

Assembly Types | VB.Net Tutorial For Biginners PDF Download

    Assemblies can be single file assemblies or multi file assemblies. In multi file assemblies one of the files must contain the assembly’s manifest data. Multi file assemblies can have only one entry point even though the assembly can contain multiple code modules. A multi file assembly is created primarily for combining modules written in different programming languages. Once the assembly is created, the file that contains the assembly manifest (and hence the assembly) can be signed, or one can give the file (and the assembly) a strong name and put it in the global assembly cache.
     Main uses of multi file assembly are for combining modules written in different programming languages. They enable optimization of downloading an application by putting seldom-used types in a module that is downloaded only when needed. The .NET Framework downloads a file only when it is referenced; keeping infrequently referenced code in a separate file from the application optimizes code download.
   Let us look at an example of how to create multi file assembly.

AddModule.cs
Copy and Paste the following code into Notepad and save it as or AddModule.vb, depending on the language that you are using
Code Listing in C#
using System;
public class AddClass
{
public int Add(int Operand1, int Operand2)
{
return Operand1 + Operand2;
}
}
Compiling in C#
/Compilation csc /r:System.dll /t:Module AddModule.cs
Code Listing in VB.NET
Imports System
Public Module AddModule
Public Class AddClass
Function Add(ByVal Operand1 As Integer, ByVal Operand2 As Integer) As Integer
Add = Operand1 + Operand2
End Function
End Class
End Module
Compiling in VB.NET
vbc /r:System.dll /t:Module AddModule.vb
This file is compiled with the target option as module. Hence an assembly is not created.
The output is a file with an extension of .netmodule.
Similarly create SubtractModule.cs/ as shown below
SubtractModule.vb
Code Listing in C#
using System;
public class SubtractClass
{
public int Subtract(int Operand1 , int Operand2 )
{
return Operand1 - Operand2;
}
}
Compiling in C#
csc /r:System.dll /t:Module SubtractModule.cs
Code Listing in VB.NET
Imports System
Public Module SubtractModule
Public Class SubtractClass
Function Subtract(ByVal Operand1 As Integer, ByVal Operand2 As Integer) As
Integer
Subtract = Operand1 - Operand2
End Function
End Class
End Module
Compiling in VB.NET
vbc /r:System.dll /t:Module SubtractModule.vb
Now create the main module, which references the above modules. The code is as shown
below for MainModule.cs/MainModule.vb
MainModule.cs
Code Listing in C#
using System;
public class MainModule
{
public static void Main()
{
int iOperand1, iOperand2, iResult ;
iOperand1 = 22;
iOperand2 = 11;
iResult = 0;
AddClass objAddClass = New AddClass();
SubtractClass objSubtractClass = New SubtractClass();
iResult = objAddClass.Add(iOperand1, iOperand2);
Console.WriteLine(iResult.ToString());
iResult = objSubtractClass.Subtract(iOperand1, iOperand2);
Console.WriteLine(iResult.ToString());
Console.ReadLine();
}
}
Compiling in C#
Compilation csc /r:System.dll MainModule.cs
Code Listing in VB.NET
Imports System
Public Module MainModule
Sub Main()
Dim iOperand1, iOperand2, iResult As Integer
iOperand1 = 22
iOperand2 = 11
iResult = 0
Dim objAddClass As New AddClass
Dim objSubtractClass As New SubtractClass
iResult = objAddClass.Add(iOperand1, iOperand2)
Console.WriteLine(iResult.ToString)
iResult = objSubtractClass.Subtract(iOperand1, iOperand2)
Console.WriteLine(iResult.ToString)
Console.ReadLine()
End Sub
End Module
Compiling in VB.NET
vbc /r:System.dll MainModule.vb
The code is compiled as follows
To create a multi file assemble, which contains the two modules created previously
namely AddModule and SubtractModule, compile using the following command at the
command prompt
Compiling in C#
csc /System.dll /addModule:AddModule.netmodule
/addModule:SubtractModule.netmodule MainModule.cs
Compiling in VB.NET
Vbc /System.dll /addModule:AddModule.netmodule
/addModule:SubtractModule.netmodule MainModule.vb
This process creates a multi file assembly. This assembly contains the two modules
created previously namely AddModule and SubtractModule. Thus this assembly contains
multiple modules. If ildasm utility is executed on the MainModule assembly, it shows
that the manifest information in the MainModule contains references to the AddModule
and the SubtractModule modules. That is the modules are linked to the main assembly by
the information contained in the main assembly’s manifest information.

Introduction | VB.Net Tutorial For Biginners PDF Download

   In Microsoft .NET, when an application is compiled, the output of the compilation produces what is known as an Assembly. Two types of assemblies can be produced by the compilation procedure. One is the executable file (*.exe) and the other is a dynamic link library file (*.dll). Basically the assembly is the unit of deployment in Microsoft .NET and it can be thought of as a collection of types and resources that form a logical unit of functionality.
    An assembly is a self-describing entity. It contains all information about the types (classes) contained in the assembly, all external references needed for executing the assembly and so on. This is possible with an assembly manifest. The manifest contains assembly’s identity and version information, a file table containing all files that make up the assembly and the assembly reference list for all external dependencies. Thus
assemblies do not need to depend on the registry values for compilation or execution.
    An assembly contains manifest data and one or more modules. Manifest data contains information about the assembly and other list of assemblies that it depends on. It also contains all the publicly exposed types and resources. An assembly contains various modules. Each module contains metadata and IL.
  Assemblies can be viewed by application developers with the help of a tool called ildasm (IL Disassembler) provided by the .NET Framework.

Assemblies and Application Domains | VB.Net Tutorial For Biginners PDF Download

In Microsoft .NET, when an application is compiled, the output of the compilation produces what is known as an Assembly.

Nesting try/catch/finally blocks and re-throwing exceptions | VB.Net Tutorial For Biginners PDF Download

It should be noted that structured exception handling allows you to nest try/catch/finally blocks within one another. This allows multiple levels of nesting and if the inner catch blocks cannot handle a specific exception type, the runtime will look for a matching catch handler in one of the outer try blocks. This repeats until a matching catch handler is found in one of the enclosing blocks. If the outermost try block is reached and no such matching catch handler is found, the runtime forces an unhandled exception to be raised. Let’s take
a look at a quick example of how to nest try/catch/finally blocks within one another.
Code listing in C#
using System;
class HelloNested
{
static void Main(string[] args)
{
try
{
try
{
throw new Exception("It's just too warm in here !");
}
catch(Exception exInner)
{
// Display the exception message
Console.WriteLine("Inner catch caught an exception: {0}", exInner.Message);
}
finally
{
// The inner finally block that executes always
Console.WriteLine("Inner finally");
}
// Continue execution in the Outer try block
Console.WriteLine("Continue executing in Outer ...");
}
catch(Exception exOuter)
{
// Display the exception message
Console.WriteLine("Outer catch caught an exception: {0}", exOuter.Message);
}
finally
{
// The outer finally block that executes always
Console.WriteLine("Outer finally");
}
}
}
Code listing in VB.NET
 Imports System
Module HelloNested
Sub Main()
' This is the beginning of the Outer Try block
Try
' This is the beginning of the Inner Try block
Try
Throw New Exception("It's just too warm in here !")
Catch exInner As Exception
' Display the exception message
Console.WriteLine("Inner catch caught an exception: {0}", _ exInner.Message)
Finally
' The inner finally clause that executes always Console.WriteLine("Inner finally")
' The Inner Try/Catch/Finally blocks ends here
End Try
' Continue execution in the Outer try block
Console.WriteLine("Continue executing in Outer ...")
Catch exOuter As Exception
' Display the exception message
Console.WriteLine("Outer catch caught an exception: {0}", _ exOuter.Message)
Finally
' The outer finally clause that executes always Console.WriteLine("Outer finally")
' The Outer Try/Catch/Finally blocks ends here
End Try
End Sub
End Module
   As shown in the example above, we have an inner try/catch/finally triad nested within an outer try block. The code within the inner try block raises an exception, so the runtime will check to see if one of the inner catch handlers will be able to handle the exception. Only when none of the inner catch handlers can handle that exception type, will the catch handlers of the outer try block be examined if they’ll be able to handle the error.
   Save the example shown above in a file named HelloNested.cs/HelloNested.vb. Compile the application by running the following command from the DOS command line:
Compiling in C#
csc /target:exe HelloNested.cs
Compiling in VB.NET
vbc /target:exe HelloNested.vb
Run the program HelloNested.exe and observe the output:
Inner catch caught an exception : It's just too warm in here !
Inner finally
Continue executing in Outer ...
Outer finally
As seen from the output above, the inner catch handler catches an exception raised by the code in the inner try block since it can handle System.Exception exceptions. Now replace the inner catch block in the above example to handle only System.OverflowException exceptions.
Code listing in C#
catch(OverflowException exInner)
{
// Display the exception message
Console.WriteLine("Inner catch caught an exception: {0}", exInner.Message);
}
Code listing in VB.NET
Catch exOverflow As OverflowException
' Display the exception message
Console.WriteLine("Inner catch caught an overflow exception: {0}", _ exOverflow.Message)
Compile and run the modified program HelloNested.exe and observe the output:
Inner finally
Outer catch caught an exception : It's just too warm in here !
Outer finally
     Notice that since the inner catch block can handle only System.OverflowException exceptions the runtime looks for a matching catch handler in the outer blocks and locates the outer catch handler, which subsequently handles the System.Exception exception.
    Until now, we’ve seen how exceptions are raised by code enclosed within the try block. But also take note that you can throw exceptions from within catch and finally blocks too. There are times when a catch handler catches an exception and examines it only to find that it cannot handle the exception. In such cases, the catch handler can re-throw the exception hoping that one of the outer catch handlers will be able to catch the exception and handle it appropriately. In this case, the runtime checks for a matching catch handler
in one of the enclosing outer catch blocks to handle the re-thrown exception. Let’s modify the earlier example to re-throw the exception that we caught in the inner catch block. Modify the inner catch block in the HelloNested code as shown below:
Code listing in C#
// Rest of the code omitted for brevity . . .
try
{
try
{
throw new Exception("It's just too warm in here !");
}
catch(Exception exInner)
{
// Display the exception message
Console.WriteLine("Inner catch caught an exception: {0}", exInner.Message);
// Rethrow the exception
throw exInner;
}
finally
{
// The inner finally block that executes always
Console.WriteLine("Inner finally");
}
// Continue execution in the Outer try block
Console.WriteLine("Continue executing in Outer ...");
}
// Rest of the code omitted for brevity . . .
Code listing in VB.NET

' Rest of the code omitted for brevity . . .
' This is the beginning of the Inner Try block
Try
Throw New Exception("It's just too warm in here !")
Catch exInner As Exception
' Display the exception message
Console.WriteLine("Inner catch caught an exception: {0}", exInner.Message)
' Rethrow the exception
Throw exOverflow
Finally
' The inner finally clause that executes always
Console.WriteLine("Inner finally")
' The Inner Try/Catch/Finally blocks ends here
End Try
' Rest of the code omitted for brevity . . .
   You will notice that the inner catch block re-throws the exception that it catches and hopes that one of the outer catch handlers will be able to handle it. Compile and run the application. Observe the output:
Inner catch caught an exception : It's just too warm in here !
Inner finally
Outer catch caught an exception : It's just too warm in here !
Outer finally
   You’ll notice that both the inner and the outer catch handlers have a go at handling the exception. The inner catch block catches the exception and re-throws it. The re-thrown exception is then subsequently caught and handled by the outer catch handler. Take note that you can throw exceptions from finally blocks too.

How the CLR uses the call-stack to locate a matching catch handler:
   When an exception occurs, the CLR tries to locate an appropriate catch handler (associated with the current try block), which is capable of handling the exception. If it cannot find an appropriate catch handler, then the next outer try-catch block is examined for appropriate catch handlers. This search continues until it finds a matching catch handler within the scope of the currently executing method (in C#) / procedure (in
VB.NET). If it still cannot find a matching catch handler within the scope of the currently executing method/procedure, it pops the current method/procedure out of the call-stack thus causing the current method to lose scope, and then searches for matching catch handlers in the next method (the method that had originally called the current method/procedure) in the call-stack. If it cannot find a matching catch handler there too, it pops this method/procedure out and examines the next one in the call-stack. This stack unwinding continues until a matching catch handler is found for the exception that was thrown. If no such matching catch handler is found when the stack is completely unwound, then the exception becomes an unhandled exception.
  Code listing in C#
using System;
// Rest of the code omitted for brevity...
class Diver
{
static void Main(string[] args)
{
try
{
Console.WriteLine("Get Set Go...");
// Call the DiveIn() static method
Diver.DiveIn();
}
catch(SharkAttackException ex)
{
Console.WriteLine(ex.Message);
}
finally
{
// This should always get called
Console.WriteLine("In Main finally");
}
}
static void DiveIn()
{
try
{
// Call the DiveDeeper static method
Diver.DiveDeeper();
}
catch(WaterTooColdException ex)
{
Console.WriteLine(ex.Message);
}
finally
{
// This should always get called
Console.WriteLine("In DiveIn finally");
}
}
static void DiveDeeper()
{
try
{
throw new SharkAttackException("Two hungry Great-White sharks " + "on the prowl");
}
catch(OutOfOxygenException ex)
{
Console.WriteLine(ex.Message);
}
finally
{
// This should always get called
Console.WriteLine("In DiveDeeper finally");
}
}
}
Code listing in VB.NETImports System
' Rest of the code omitted for brevity...
Module Diver
Sub Main()
Try
Console.WriteLine("Get Set Go...")
' Call the DiveIn() subroutine
Call DiveIn
Catch ex As SharkAttackException
Console.WriteLine(ex.Message)
Finally
' This should always get called
Console.WriteLine("In Main finally")
End Try
End Sub
Sub DiveIn()
Try
' Call the DiveDeeper() subroutine
Call DiveDeeper
Catch ex As WaterTooColdException
Console.WriteLine(ex.Message)
Finally
' This should always get called
Console.WriteLine("In DiveIn finally")
End Try
End Sub
Sub DiveDeeper()
Try
Throw New SharkAttackException("Two hungry Great-White sharks " + _
"on the prowl")
Catch ex As OutOfOxygenException
Console.WriteLine(ex.Message)
Finally
' This should always get called
Console.WriteLine("In DiveDeeper finally")
End Try
End Sub
End Module
Compile the application by running the following command from the DOS command line:
Compiling in C#
csc /target:exe Diver.cs
Compiling in VB.NET
vbc /target:exe Diver.vb
Run the program Diver.exe and observe the output:
Get Set Go...
In DiveDeeper finally
In DiveIn finally
Two hungry Great-White sharks on the prowl
In Main finally
   In the above code fragment, the Main() entry point in the program calls the DiveIn() method (in C#) / Subroutine (in VB.NET), which in turn calls the DiveDeeper() method/subroutine. Notice that the DiveDeeper() method throws a custom application-defined exception called SharkAttackException.
Explanation using C#
Image
Explanation using VB.NET
Image
    When the SharkAttackException exception is thrown the CLR checks to see if the catch handlers associated with the try block in DiveDeeper() can handle the exception Since the only exception type handled by the catch handler in DiveDeeper() happens to be OutOfOxygenException, the CLR will pop the DiveDeeper() method out of the stack after executing the finally block in DiveDeeper(). It will then go on to search for a suitable catch handler in the next method/procedure in the call-stack, which happens to be the DiveIn() method/subroutine. Since the try-catch block in the DiveIn() method also happens to have a catch handler that handles only WaterTooColdException exceptions, this method/procedure is also popped out of the call-stack after executing its finally block. The Main() method/subroutine, which is the next in the call-stack is then examined for matching catch handler within the try-catch block. As you can see, the try-catch block within the Main() method/subroutine does have a catch handler that can handle the SharkAttackException and so control is eventually passed over to this catch handler after which the corresponding finally block is executed. Assuming that the Main() entry-point method/subroutine did not have an appropriate catch handler too, then the next pop operation would have completely unwound the call-stack thereby making the SharkAttackException an unhandled exception
Catching arithmetic overflow exceptions with C#’s checked keyword:
   Never ever discount the destructive effects that arithmetic overflow exceptions bring to
the stability of your software. For starters, recollect the tragic crash of the $7 billion
Ariane 5 rocket – A crash that resulted because its software system attempted to convert
a 64-bit floating-point number to a signed 16-bit integer, which subsequently caused an
overflow exception, and worse yet, there was no exception handler to handle this
exception. Sadly enough, the backup systems were also running on the same copy of the
software, without the exception handler. Read an account of the Ariane 5 crash at:
http://www.cs.ucsd.edu/users/goguen/courses/230/ariane5nyt.pdf

   Let’s face it – How many times have we been in situations where we’ve stared in disbelief at our program spewing some insanely odd numerical output on arithmetic operations when it’s fairly obvious that the output is in not even slightly connected to what was expected of the program. Let’s quickly see what we mean here with an example. Consider the following C# program:
using System;
class ByteBites
{
static void Main(string[] args)
{
byte b1 = 57;
byte b2 = 200;
byte bResult = (byte)(b1 + b2);
Console.WriteLine("{0} + {1} = {2}", b1, b2, bResult);
}
}
Save this program to a file called ByteBites.cs. Compile the program using the following command from the DOS command line:csc /target:exe ByteBites.cs
Run ByteBites.exe and observe the output:
57 + 200 = 1
    Many of us know what went wrong here. It’s fairly obvious here that a byte data type can hold only values from 0 to 255. Yet we are trying to add two bytes whose result over shoots the range of values that the resultant byte can hold, resulting in an overflow, and hence the absurd result 1. This is what the less wary among us (at least I do) run into when choosing data types to work with, paying little attention to the range of data that the program expects these data types to store and handle. A subtle arithmetic addition operation that has the potential to generate an overflow operation is enough to send your application to the tomb. Most often, good testing practices catch these bugs during the testing phase. But it certainly might get past the QA team if the test data being fed to the program is not very exhaustive and if every possible test case is not being taken into account – The Ariane 5 crash of 1996 is a testimony to that. So as developers, we need to
code defensively to catch such arithmetic overflow errors and handle them appropriately in the execution flow of the program as our application logic dictates, thus leaving no room for inconsistent or incorrect results to bring down the application to a grinding halt.
      So let’s see where C# can help us here. C# provides the checked keyword to trap and handle such arithmetic overflows. When an arithmetic operation that is enclosed within a checked block (or checked expression) results in an overflow, the runtime generates a System.OverflowException. Compare this to our previous example where the overflow result was silently assigned to the resulting byte. So let’s modify the previous example to enclose the arithmetic addition of the two bytes within a checked block. The modified
code is shown below:
using System;
class ByteBites
{
static void Main(string[] args)
{
try
{
checked
{
byte b1 = 57;
byte b2 = 200;
byte bResult = (byte)(b1 + b2);
Console.WriteLine("{0} + {1} = {2}", b1, b2, bResult);
}
}
catch(OverflowException exOverflow)
{
Console.WriteLine("Caught overflow exception: {0}",
exOverflow.Message);
}
}
}
   You’ll notice that we now have a checked block that encloses the arithmetic operation, which in turn is enclosed within a try block. Compile and run the application. Notice the output:
Caught overflow exception: Arithmetic operation resulted in an overflow.
    You’ll notice that the addition operation generated a System.OverflowException because it was enclosed within a checked block. Remove the checked block and you’ll notice that you’ll again get back the cryptic 1 as the result. But then, wouldn’t it be asking too much if we had to put each and every arithmetic operation that had the potential to generate an overflow within a checked block. Thankfully, there’s an easier way to turn on arithmetic overflow checking for the entire application by using the /checked compiler option when
compiling your application. To test this, go ahead and remove the checked block that is enclosing the addition operation. This time compile the program with the /checked switch turned on, by typing the following command in the DOS command line:
csc /target:exe /checked ByteBites.cs
Run the program and observe the output that the program spews out:
Caught overflow exception: Arithmetic operation resulted in an overflow.
    Notice that the /checked option has the same effect as using the checked block around your arithmetic operations. This option thereby allows you to enforce arithmetic overflow checks and to catch such exceptions throughout your application. So what if you’ve turned on the /checked option and want to selectively prevent certain parts in your application from generating an overflow exception when an overflow occurs. For example, assume you have a scenario where you need the check the value of the overflowed result to determine what action to take and so on. In such cases, you can use the unchecked keyword and enclose those arithmetic operations within an unchecked block so that an OverflowException is not generated for those operations. This is shown in the snippet of code below:
unchecked
{
byte b1 = 57;
byte b2 = 200;
byte bResult = (byte)(b1 + b2);
Console.WriteLine("{0} + {1} = {2}", b1, b2, bResult);
}
   Of course, the above code fragment gives you yet another opportunity to see the infamous 1 as the result.
Using the checked keyword and /checked compiler option judiciously in your C# applications can help you catch arithmetic overflow exceptions and to ensure that your application stays sane.

Understanding Application exceptions (user-defined or custom exceptions)


   Though the FCL supports a great deal of predefined system exception classes (as seen in the earlier section) that can be used to represent a large gamut of errors, there is always a need to model custom errors that represent failed run-of-the-mill business logic as well as other application specific error scenarios. In these situations, you need to turn to defining your own custom exceptions that are application specific. When defining application specific custom exceptions, you need to typically create a class that is derived from the
System.ApplicationException class.
    It is good practice and generally recommended that the application exception class be suffixed with Exception. For example, if you need to define an exception that indicates that a specific ticket to a movie is not available, you’d probably want to name it something like TicketNotAvailableException.
   So let’s put this in practice and see how to define and use a custom application exception. The example we’ll take up is a class that simulates a television channel changer, which allows the user to surf television channels. We’ll assume that one of our business logic constraints is that we support only 80 channels and that the class is expected to flip channels only if the user enters a channel number between 1 and 80. If the user enters an invalid channel number, the class is expected throw an application exception, which indicates that the channel number entered is invalid. So let’s put together this application-specific exception class.
    We’ll call the exception class ChannelNotAvailableException and derive this class from the System.ApplicationException class to indicate that this is an application specific exception. Next, we’ll have to create some constructors for this class. The best practice guidelines for exception handling recommend that we have two constructors in addition to the default no-argument constructor - One constructor that accepts the error message as a parameter and the other one that accepts both an error message and an inner exception as a parameter. Let’s take a look at the ChannelNotAvailableException class.
Code listing in C#
class ChannelNotAvailableException : System.ApplicationException
{
public ChannelNotAvailableException()
{
}
public ChannelNotAvailableException(String errorMessage) :
base(errorMessage)
{
}
public ChannelNotAvailableException(String errorMessage,
Exception innerException) : base(errorMessage, innerException)
{
}
}
Code listing in VB.NET
Public Class ChannelNotAvailableException
Inherits ApplicationException
' Default Constructor
Public Sub New()
' Call the base class constructor
MyBase.New()
End Sub
' Constructor that takes message string
Public Sub New(ByVal errorMessage As String)
' Call the base class constructor
MyBase.New(errorMessage)
End Sub
' Constructor that takes message string and inner exception
Public Sub New(ByVal errorMessage As String, _
ByVal innerException As Exception)
' Call the base class constructor
MyBase.New(errorMessage, innerException)
End Sub
End Class
   The ChannelNotAvailableException class shown above is fairly trivial and you’ll notice that the non-default constructors do nothing more than initializing their corresponding base class counter parts through the base class argument-list initializer. That’s it – we’re done setting up our custom exception class. We’ll see how to put this to use in our TV channel surfer application. Let’s put together some code for the channel surfer class.
Code listing in C#
class ChannelSurfer
{
private const int MAX_CHANNELS = 80;
private int m_nCurrentChannel;
ChannelSurfer()
{
// Set channel 1 as the default
m_nCurrentChannel = 1;
}
public int CurrentChannel
{
get
{
// Return the current channel
return m_nCurrentChannel;
}
}
// Rest of the class implementation goes here . . .
}
Code listing in VB.NET
Public Class ChannelSurfer
Private Const MAX_CHANNELS As Integer = 80
Private m_nCurrentChannel As Integer
Public Sub New()
MyBase.New()
' Set channel 1 as the default
Me.m_nCurrentChannel = 1
End Sub
ReadOnly Property CurrentChannel() As Integer
Get
' Return the current channel
Return Me.m_nCurrentChannel
End Get
End Property
' Rest of the class implementation goes here . . .
End Class
The channel surfer class supports a read-only property named CurrentChannel that keeps track of the current channel being viewed. The viewer can move between channels by calling the FlipToChannel() method shown below:
Code listing in C#
class ChannelSurfer
{
// Rest of the class implementation goes here . . .
void FlipToChannel(int nChannelNumber)
{
if( (nChannelNumber < 1) || (nChannelNumber > MAX_CHANNELS))
{
throw new ChannelNotAvailableException("We support only 80 channels."
+ "Please enter a number between 1 and 80");
}
else
{
// Set the value of the current channel
m_nCurrentChannel = nChannelNumber;
}
}
}
Code listing in VB.NET
Public Class ChannelSurfer
' Rest of the class implementation goes here . . .
Sub FlipToChannel(ByVal nChannel As Integer)
If ((nChannel < 1) Or (nChannel > MAX_CHANNELS)) Then
' Raise an exception
Throw New ChannelNotAvailableException("We support only 80 channels." _
+ "Please enter a number between 1 and 80")
Else
' Set the current channel
Me.m_nCurrentChannel = nChannel
End If
End Sub
End Class
As seen above the FlipToChannel() method checks to see if the channel number that the user is requesting is between 1 and 80 and if so, sets the value of the CurrentChannel property to the requested channel. If the values are not within the specified range, the class throws the user-defined ChannelNotAvailableException exception. Let’s use the application’s Main() entry point as a test harness for the ChannelSurfer class. Take a look at the code below:
Code listing in C#
class ChannelSurfer
{
// Rest of the class implementation goes here . . .
static void Main(string[] args)
{
ChannelSurfer channelZapper = new ChannelSurfer();
// Display a message
Console.WriteLine("Press 'Q' or 'q' to quit zapping channels");
// Set up an infinite loop
for(;;)
{
try
{
// It's channel surfing time folks!
Console.Write("Please enter a channel number and press 'Enter'");
// Get the channel number from the user
String strChannel = Console.ReadLine();
// Check if the user wants to quit
if(strChannel.Equals("Q") || strChannel.Equals("q")) break;
// Convert the channel number to an integer
int nChannel = Int32.Parse(strChannel);
// Flip away to the requested channel
channelZapper.FlipToChannel(nChannel);
}
catch(ChannelNotAvailableException exChannel)
{
Console.WriteLine("Channel not supported: {0}", exChannel.Message);
}
catch(FormatException exFormat)
{
Console.WriteLine("Caught a format exception: {0}",
exFormat.Message);
}
catch(Exception ex)
{
Console.WriteLine("Caught a exception: {0}", ex.Message);
}
finally
{
// What channel are we watching?
Console.WriteLine("You are watching Channel : {0}",
channelZapper.CurrentChannel);
}
}
}
}
Code listing in VB.NET
Module SurfChannelTestHarness
Sub Main()
Dim channelZapper As ChannelSurfer = New ChannelSurfer()
' Display a message
Console.WriteLine("Press 'Q' or 'q' to Quit zapping Channels")
' Setup an infinite loop to ask the user for channel input
Do
Try
' It's channel surfing time folks !
Console.Write("Please enter a channel number and press 'Enter' ")
' Get the channel number from the user
Dim strChannel As String = Console.ReadLine()
' Check if the user wants to quit
If (strChannel.Equals("Q") Or strChannel.Equals("q")) Then
Exit Do
End If
' Convert the channel number to an integer
Dim nChannel As Integer = Int32.Parse(strChannel)
' Flip away to the requested channel
channelZapper.FlipToChannel(nChannel)
Catch exChannel As ChannelNotAvailableException
Console.WriteLine("Channel not supported: {0}", _
exChannel.Message)
Catch exFormat As FormatException
Console.WriteLine("Caught a format exception: {0}", _
exFormat.Message)
Catch ex As Exception
Console.WriteLine("Caught a exception: {0}", ex.Message)
Finally
' What channel are we watching ?
Console.WriteLine("You are watching Channel: {0}", _
channelZapper.CurrentChannel)
End Try
Loop While True
End Sub
End Module
The Main() entry point creates an instance of the ChannelSurfer class and sets up a loop that requests channel numbers from the user until the user presses the ‘Q’ or ‘q’ key to quit the application. When the channel number input is received, it calls the FlipToChannel() method of the ChannelSurfer object. The FlipToChannel() method call is enclosed within a try block and an appropriate catch handler for the
ChannelNotAvailableException will catch the exception if an invalid channel number is passed to the FlipToChannel() method. Also, if the user enters non-numeric input, the Int32.Parse() method will throw a System.FormatException that will be caught by the catch handler that we’ve setup to handle FormatException exceptions. Compile the file using the following command from the DOS command line:
Compiling in C#
csc /target:exe ChannelSurfer.cs
Compiling in VB.NET
vbc /target:exe ChannelSurfer.vb
   That generates the executable file ChannelSurfer.exe. Run the application and feed it with input containing both valid and invalid input values. Here’s a sample interaction with the ChannelSurfer application.
Press 'Q' or 'q' to quit zapping channels
Please enter a channel number and press 'Enter' 62
You are watching Channel : 62
Please enter a channel number and press 'Enter' 56
You are watching Channel : 56
Please enter a channel number and press 'Enter' 104
Channel not supported: We support only 80 channels. Please enter a number between 1 and 80
You are watching Channel : 56
Please enter a channel number and press 'Enter' abcd
Caught a format exception : Input string was not in a correct format.
You are watching Channel : 56
Please enter a channel number and press 'Enter' 15
You are watching Channel : 15
Please enter a channel number and press 'Enter' q
You are watching Channel : 15
   You will notice from the output above that when the user enters 104 for the channel number, the ChannelNotAvailableException is thrown from the FlipToChannel() method, which is then handled by the catch handler. Similarly, when the user keys in a non-numeric value such as abcd, a System.FormatException is raised by the Int32.Parse() method, which then gets caught by the catch handler that filters the FormatException exceptions. Using application specific exceptions like ChannelNotAvailableException
allows you to build exception-handling classes around your business-logic and application specific scenarios. Be sure to check if the framework provides a predefined exception class that suits the exception type that you want to handle. If so, reuse FCL provided system exceptions. Otherwise, feel free to model custom exception classes that are modeled around application specific exception scenarios.

Handling exceptions that are not System.Exception compliant


What happens when your managed .NET code interacts with legacy libraries that are .NET agnostic. In general cases, when you interact with unmanaged code using the Platform Invoke (P/Invoke) or COM Interoperability mechanisms provided by the .NET framework, an exception raised from unmanaged code would be mapped back by the CLR into an appropriate .NET exception type. However, there are cases where legacy unmanaged libraries could possibly raise exceptions that are not System.Exception compliant, which cannot be mapped to a corresponding .NET exception type. In such cases, you can use a generic exception handler that can catch errors that are not .NET aware and not compliant with System.Exception. The generic catch handler contains only the catch keyword and does not specify an exception type filter. Here’s an example code snippet with a generic catch handler:
Code listing in C#
try
{
// This is the try block
}
catch(Exception ex)
{
// This is the catch block to handle System.Exception errors
}
catch
{
// This is a generic catch block to handle calls to libraries that raise
// exceptions which are not compliant with System.Exception. Can catch
// any error that the other catch handlers cannot handle.
}
finally
{
// This is the finally block
}


Code listing in VB.NET
Try
' This is the Try block
Catch ex As Exception
' This is the catch block to handle System.Exception errors
Catch
' This is a generic catch block to handle calls to libraries that raise
' exceptions which are not compliant with System.Exception. Can catch
' any error that the other catch handlers cannot handle.
Finally
' This is the finally block
End Try