Saturday, 7 April 2012

C Sharp Tutorials/Lesson 11 Lesson 11: Indexers


This lesson teaches C# Indexers. Our objectives are as follows:
  • Understand What Indexers Are For.
  • Implement an Indexer.
  • Overload Indexers.
  • Understand How to Implement Multi-Parameter Indexers.
Indexers are real easy. They allow your class to be used just like an array. On the inside of a class, you manage a collection of values any way you want. These objects could be a finite set of class members, another array, or some complex data structure. Regardless of the internal implementation of the class, its data can be obtained consistently through the use of indexers. Here's an example.
Listing 11-1. An Example of An Indexer: IntIndexer.cs
using System;
/// 

/// A simple indexer example./// 

class IntIndexer
{
private string[] myData;
public IntIndexer(int size)
{
myData = 
new string[size];
for (int i=0; i < size; i++)
{
myData[i] = "empty";
}
}

public
 string this[int pos]
{
get
{return myData[pos];
}
set
{
myData[pos] = 
value;
}
}

static
 void Main(string[] args)
{
int size = 10;

IntIndexer myInd = 
new IntIndexer(size);

myInd[9] = "Some Value";
myInd[3] = "Another Value";
myInd[5] = "Any Value";

Console.WriteLine("\nIndexer Output\n");

for
 (int i=0; i < size; i++)
{
Console.WriteLine("myInd[{0}]: {1}", i, myInd[i]);
}
}
}
Listing 11-1 shows how to implement an Indexer. The IntIndexer class has a string array named myData. This is a private array that external users can't see. This array is initialized in the constructor, which accepts an int size parameter, instantiates the myData array, and then fills each element with the word "empty".
The next class member is the Indexer, which is identified by the this keyword and square brackets, this[int pos]. It accepts a single position parameter, pos. As you may have already guessed, the implementation of an Indexer is the same as a Property. It has get andset accessors that are used exactly like those in a Property. This indexer returns a string, as indicated by the string return value in the Indexer declaration.
The Main() method simply instantiates a new IntIndexer object, adds some values, and prints the results. Here's the output:
Indexer Output

myInd[0]: empty
myInd[1]: empty
myInd[2]: empty
myInd[3]: Another Value
myInd[4]: empty
myInd[5]: Any Value
myInd[6]: empty
myInd[7]: empty
myInd[8]: empty
myInd[9]: Some Value
Using an integer is a common means of accessing arrays in many languages, but the C# Indexer goes beyond this. Indexers can be declared with multiple parameters and each parameter may be a different type. Additional parameters are separated by commas, the same as a method parameter list. Valid parameter types for Indexers include integers,enums, and strings. Additionally, Indexers can be overloaded. In listing 11-2, we modify the previous program to accept overloaded Indexers that accept different types.
Listing 11-2. Overloaded Indexers: OvrIndexer.cs
using System;
/// 

/// Implements overloaded indexers./// 

class OvrIndexer
{
private string[] myData;private int arrSize;
public OvrIndexer(int size)
{
arrSize = size;
myData = 
new string[size];
for (int i=0; i < size; i++)
{
myData[i] = "empty";
}
}

public
 string this[int pos]
{
get
{return myData[pos];
}
set
{
myData[pos] = 
value;
}
}

public
 string this[string data]
{
get
{int count = 0;
for
 (int i=0; i < arrSize; i++)
{
if (myData[i] == data)
{
count++;
}
}
return count.ToString();
}
set
{for (int i=0; i < arrSize; i++)
{
if (myData[i] == data)
{
myData[i] = 
value;
}
}
}
}

static
 void Main(string[] args)
{
int size = 10;
OvrIndexer myInd = 
new OvrIndexer(size);

myInd[9] = "Some Value";
myInd[3] = "Another Value";
myInd[5] = "Any Value";

myInd["empty"] = "no value";

Console.WriteLine("\nIndexer Output\n");

for
 (int i=0; i < size; i++)
{
Console.WriteLine("myInd[{0}]: {1}", i, myInd[i]);
}

Console.WriteLine("\nNumber of \"no value\" entries: {0}", myInd["no value"]);
}
}
Listing 11-2 shows how to overload Indexers. The first Indexer, with the int parameter, pos, is the same as in Listing 11-1, but there is a new Indexer that takes a string parameter. The get accessor of the new indexer returns a string representation of the number of items that match the parameter value, data. The set accessor changes each entry in the array that matches the data parameter to the value that is assigned to the Indexer.
The behavior of the overloaded Indexer that takes a string parameter is demonstrated in the Main() method of Listing 11-2. It invokes the set accessor, which assigns the value of "no value" to every member of the myInd class that has the value of "empty". It uses the following command: myInd["empty"] = "no value";. After each entry of the myInd class is printed, a final entry is printed to the console, indicating the number of entries with the "no value" string. This happens by invoking the get accessor with the following code: myInd["no value"]. Here's the output:
Indexer Output

myInd[0]: no value
myInd[1]: no value
myInd[2]: no value
myInd[3]: Another Value
myInd[4]: no value
myInd[5]: Any Value
myInd[6]: no value
myInd[7]: no value
myInd[8]: no value
myInd[9]: Some Value

Number of "no value" entries: 7
The reason both Indexers in Listing 11-2 can coexist in the same class is because they have different signatures. An Indexer signature is specified by the number and type of parameters in an Indexers parameter list. The class will be smart enough to figure out which Indexer to invoke, based on the number and type of arguments in the Indexer call. An indexer with multiple parameters would be implemented something like this:
public object this[int param1, ..., int paramN]
{
get
{// process and return some class data
}
set
{
// process and assign some class data
}
}

C Sharp Tutorials/Lesson 12 Lesson 12: Structs


This lesson teaches C# Structs. Our objectives are as follows:
  • Understand the Purpose of structs.
  • Implement a struct.
  • Use a struct.
A struct allows you to create new value-type objects that are similar to the built-in types (int, float, bool, etc.). When would you use a struct instead of a class? Think about how the built-in types are used. They have values and distinct operations to manipulate those values. If you have a need to create an object that behaves in this manner, consider implementing it as a struct. Later in this article, I'll explain a couple rules for using structs, which will give you a better idea of when to use them. In the meantime, here's an example.
Listing 12-1. Example of a struct: StructExample.cs
using System;
struct Point
{
public int x;public int y;
public
 Point(int x, int y)
{
this.x = x;this.y = y;
}

public
 Point Add(Point pt)
{
Point newPt;

newPt.x = x + pt.x;
newPt.y = y + pt.y;

return
 newPt;
}
}
/// 

/// Example of declaring and using a struct/// 

class StructExample
{
static void Main(string[] args)
{
Point pt1 = 
new Point(1, 1);
Point pt2 = 
new Point(2, 2);
Point pt3;

pt3 = pt1.Add(pt2);

Console.WriteLine("pt3: {0}:{1}", pt3.x, pt3.y);
}
}
Listing 12-1 shows how to declare and use a struct. It is easy to tell that a type is a structbecause of the keyword struct used in its definition. The basic layout of a struct is much like a class, but with differences, which will be explained in following paragraphs. The Pointstruct has a constructor which initializes its fields to the x and y values passed in. It also has a method named Add(), which will accept another Point struct, add it to this struct, and return a new struct.
Notice that there is a Point struct declared in the Add() method. It does not need to be instantiated with a new operator, like a class. When this occurs, the struct is implicitly instantiated with its default (or parameterless) constructor. The parameterless constructor initializes all struct fields to default values. i.e. integrals are 0, floating points are 0.0, and booleans are false. It's illegal to define a parameterless constructor for a struct.
Although not required, a struct may be instantiated with a new operator. In Listing 12-1 thept1 and pt2 Point structs are initialized with values by using the constructor defined in thePoint struct. A third Point struct, pt3 is declared and defaults to using the parameterless (default) constructor, because it doesn't matter what it's value is at this point. The Add()method of the pt1 struct is then invoked, passing the pt2 struct as a parameter. The result is assigned to pt3, showing that a struct may be used just like any other value type. Here's the output from Listing 12-1:
 pt3: 3:3
Another difference between structs and classes is that structs can not have destructors. Also, structs cannot inherit another class or struct or be inherited from. However, a structmay implement multiple interfaces. An interface is a C# reference type with members that do not have implementations. Any class or struct implementing an interface must implement every one of that interface's methods. Interfaces are a subject for a later lesson.

C Sharp Tutorials/Lesson 13 Lesson 13: Interfaces


This lesson teaches C# Interfaces. Our objectives are as follows:
  • Understand the Purpose of Interfaces.
  • Define an Interface.
  • Use an Interface.
  • Implement Interface Inheritance.
An interface looks like a class, but has no implementation. The only thing it contains are definitions of events, indexers, methods and/or properties. The reason interfaces only provide definitions is because they are inherited by classes and structs, which must provide an implementation for each interface member defined.
So, what are interfaces good for if they don't implement functionality? They're great for putting together plug-n-play like architectures where components can be interchanged at will. Since all interchangeable components implement the same interface, they can be used without any extra programming. The interface forces each component to expose specific public members that will be used in a certain way.
Because interfaces must be implemented by derived classes and structs, they define a contract. For instance, if class foo implements the IDisposable interface, it is making a statement that it guarantees it has the Dispose() method, which is the only member of theIDisposable interface. Any code that wishes to use class foo may check to see if class fooimplements IDisposable. When the answer is true, then the code knows that it can callfoo.Dispose(). Listing 13-1 shows how to define an interface:
Listing 13-1. Defining an Interface: MyInterface.cs
interface IMyInterface
{
void MethodToImplement();
}
Listing 13-1 defines an interface named IMyInterface. A common naming convention is to prefix all interface names with a capital "I". This interface has a single method namedMethodToImplement(). This could have been any type of method declaration with different parameters and return types. I just chose to declare this method with no parameters and avoid return type to make the example easy. Notice that this method does not have an implementation (instructions between curly braces - {}), but instead ends with a semi-colon, ";". This is because the interface only specifies the signature of methods that an inheriting class or struct must implement. Listing 13-2 shows how this interface could be used.
Listing 13-2. Using an Interface: InterfaceImplementer.cs
class InterfaceImplementer : IMyInterface
{
static void Main()
{
InterfaceImplementer iImp = 
new InterfaceImplementer();
iImp.MethodToImplement();
}

public
 void MethodToImplement()
{
Console.WriteLine("MethodToImplement() called.");
}
}
The InterfaceImplementer class in Listing 13.2 implements the IMyInterface interface. Indicating that a class inherits an interface is the same as inheriting a class. In this case, the following syntax is used:
class InterfaceImplementer : IMyInterface
Now that this class inherits the IMyInterface interface, it must implement its members. It does this by implementing the MethodToImplement() method. Notice that this method implementation has the exact same signature, parameters and method name, as defined in the IMyInterface interface. Any difference between the method signature in the interface and the method signature in the implementing class or struct will cause a compiler error. Additionally, a class or struct that inherits an interface must include all interface members; You will receive a compiler error if you don't implement all interface members.
Interfaces may also inherit other interfaces. Listing 13-3 shows how inherited interfaces are implemented.
Listing 13-3. Interface Inheritance: InterfaceInheritance.cs
using System;
interface IParentInterface
{
void ParentInterfaceMethod();
}

interface
 IMyInterface : IParentInterface
{
void MethodToImplement();
}

class
 InterfaceImplementer : IMyInterface
{
static void Main()
{
InterfaceImplementer iImp = 
new InterfaceImplementer();
iImp.MethodToImplement();
iImp.ParentInterfaceMethod();
}

public
 void MethodToImplement()
{
Console.WriteLine("MethodToImplement() called.");
}
public void ParentInterfaceMethod()
{
Console.WriteLine("ParentInterfaceMethod() called.");
}
}
The code in listing 13.3 contains two interfaces: IMyInterface and the interface it inherits,IParentInterface. When one interface inherits another, any implementing class or structmust implement every interface member in the entire inheritance chain. Since theInterfaceImplementer class in Listing 13-3 inherits from IMyInterface, it also inheritsIParentInterface. Therefore, the InterfaceImplementer class must implement theMethodToImplement() method specified in the IMyInterface interface and theParentInterfaceMethod() method specified in the IParentInterface interface.

C Sharp Tutorials/Lesson 14 Lesson 14: Introduction to Delegates and Events


This lesson introduces delegates and events. Our objectives are as follows:
  • Understand What a Delegate Is
  • Understand What an Event Is
  • Implement Delegates
  • Fire Events

Delegates

During previous lessons, you learned how to implement reference types using language constructs such as classes and interfaces. These reference types allowed you to create instances of objects and use them in special ways to accomplish your software development goals. Classes allow you to create objects that contained members with attributes or behavior. Interfaces allow you to declare a set of attributes and behavior that all objects implementing them would publicly expose. Today, I'm going to introduce a new reference type called a delegate.
A delegate is a C# language element that allows you to reference a method. If you were a C or C++ programmer, this would sound familiar because a delegate is basically a function pointer. However, developers who have used other languages are probably wondering, "Why do I need a reference to a method?". The answer boils down to giving you maximum flexibility to implement any functionality you want at runtime.
Think about how you use methods right now. You write an algorithm that does its thing by manipulating the values of variables and calling methods directly by name. What if you wanted an algorithm that was very flexible, reusable, and allowed you to implement different functionality as the need arises? Furthermore, let's say that this was an algorithm that supported some type of data structure that you wanted to have sorted, but you also want to enable this data structure to hold different types. If you don't know what the types are, how could you decide an appropriate comparison routine? Perhaps you could implement anif/then/else or switch statement to handle well-known types, but this would still be limiting and require overhead to determine the type. Another alternative would be for all the types to implement an interface that declared a common method your algorithm would call, which is actually a nice solution. However, since this lesson is about delegates, we'll apply adelegate solution, which is quite elegant.
You could solve this problem by passing a delegate to your algorithm and letting the contained method, which the delegate refers to, perform the comparison operation. Such an operation is performed in Listing 14-1.
Listing 14-1. Declaring and Implementing a Delegate: SimpleDelegate.cs
using System;
// this is the delegate declarationpublic delegate int Comparer(object obj1, object obj2);
public class Name
{
public string FirstName = null;public string LastName = null;
public
 Name(string first, string last)
{
FirstName = first;
LastName = last;
}
// this is the delegate method handler
public
 static int CompareFirstNames(object name1, object name2)
{
string n1 = ((Name)name1).FirstName;string n2 = ((Name)name2).FirstName;
if
 (String.Compare(n1, n2) > 0)
{
return 1;
}
else if (String.Compare(n1, n2) < 0)
{
return -1;
}
else{return 0;
}
}

public
 override string ToString()
{
return FirstName + " " + LastName;
}
}

class
 SimpleDelegate
{
Name[] names = 
new Name[5];
public
 SimpleDelegate()
{
names[0] = 
new Name("Joe", "Mayo");
names[1] = 
new Name("John", "Hancock");
names[2] = 
new Name("Jane", "Doe");
names[3] = 
new Name("John", "Doe");
names[4] = 
new Name("Jack", "Smith");
}

static
 void Main(string[] args)
{
SimpleDelegate sd = 
new SimpleDelegate();
// this is the delegate instantiationComparer cmp = new Comparer(Name.CompareFirstNames);

Console.WriteLine("\nBefore Sort: \n");

sd.PrintNames();
// observe the delegate argumentsd.Sort(cmp);

Console.WriteLine("\nAfter Sort: \n");

sd.PrintNames();
}

// observe the delegate parameterpublic void Sort(Comparer compare)
{
object temp;
for
 (int i=0; i < names.Length; i++)
{
for (int j=i; j < names.Length; j++)
{
// using delegate "compare" just like
// a normal method
if ( compare(names[i], names[j]) > 0 )
{
temp = names[i];
names[i] = names[j];
names[j] = (Name)temp;
}
}
}
}

public
 void PrintNames()
{
Console.WriteLine("Names: \n");

foreach
 (Name name in names)
{
Console.WriteLine(name.ToString());
}
}
}
The first thing the program in Listing 14-1 does is declare a delegate. Delegate declarations look somewhat like methods, except they have the delegate modifier, are terminated with a semi-colon (;), and have no implementation. Below, is the delegate declaration from Listing 14-1.
public delegate int Comparer(object obj1, object obj2);
This delegate declaration defines the signature of a delegate handler method that thisdelegate can refer to. The delegate handler method, for the Comparer delegate, can have any name, but must have a first parameter of type object, a second parameter of typeobject, and return an int type. The following method from Listing 14-1 shows a delegate handler method that conforms to the signature of the Comparer delegate.
public static int CompareFirstNames(object name1, object name2)
{
...
}
Note: The CompareFirstNames method calls String.Compare to compare the FirstNameproperties of the two Name instances. The String class has many convenience methods, such as Compare, for working with strings. Please don't allow the implementation of this method to interfere with learning how delegates work. What you should concentrate on is that CompareFirstNames is a handler method that a delegate can refer to, regardless of the code inside of that method.
To use a delegate, you must create an instance of it. The instance is created, similar to a class instance, with a single parameter identifying the appropriate delegate handler method, as shown below.
Comparer cmp = new Comparer(Name.CompareFirstNames);
The delegate, cmp, is then used as a parameter to the Sort() method, which uses it just like a normal method. Observe the way the delegate is passed to the Sort() method as a parameter in the code below.
sd.Sort(cmp);
Using this technique, any delegate handler method may be passed to the Sort() method at run-time. i.e. You could define a method handler named CompareLastNames(), instantiate a new Comparer delegate instance with it, and pass the new delegate to the Sort() method.

Events

Traditional Console applications operate by waiting for a user to press a key or type a command and press the Enter key. Then they perform some pre-defined operation and either quit or return to the original prompt that they started from. This works, but is inflexible in that everything is hard-wired and follows a rigid path of execution. In stark contrast, modern GUI programs operate on an event-based model. That is, some event in the system occurs and interested modules are notified so they can react appropriately. With Windows Forms, there is not a polling mechanism taking up resources and you don't have to code a loop that sits waiting for input. It is all built into the system with events.
A C# event is a class member that is activated whenever the event it was designed for occurs. I like to use the term "fires" when the event is activated. Anyone interested in theevent can register and be notified as soon as the event fires. At the time an event fires, registered methods will be invoked.
Events and delegates work hand-in-hand to provide a program's functionality. It starts with a class that declares an event. Any class, including the same class that the event is declared in, may register one of its methods for the event. This occurs through a delegate, which specifies the signature of the method that is registered for the event. The delegatemay be one of the pre-defined .NET delegates or one you declare yourself. Whichever is appropriate, you assign the delegate to the event, which effectively registers the method that will be called when the event fires. Listing 14-2 shows a couple different ways to implement events.
Listing 14-2. Declaring and Implementing Events: Eventdemo.cs
using System;using System.Drawing;using System.Windows.Forms;
// custom delegatepublic delegate void Startdelegate();
class Eventdemo : Form
{

// custom eventpublic event Startdelegate StartEvent;
public Eventdemo()
{
Button clickMe = 
new Button();

clickMe.Parent = 
this;
clickMe.Text = "Click Me";
clickMe.Location = 
new Point(
(ClientSize.Width - clickMe.Width) /2,
(ClientSize.Height - clickMe.Height)/2);
// an EventHandler delegate is assigned
// to the button's Click event
clickMe.Click += new EventHandler(OnClickMeClicked);
// our custom "Startdelegate" delegate is assigned
// to our custom "StartEvent" event.
StartEvent += new Startdelegate(OnStartEvent);
// fire our custom eventStartEvent();
}

// this method is called when the "clickMe" button is pressed
public void OnClickMeClicked(object sender, EventArgs ea)
{
MessageBox.Show("You Clicked My Button!");
}

// this method is called when the "StartEvent" Event is firedpublic void OnStartEvent()
{
MessageBox.Show("I Just Started!");
}

static
 void Main(string[] args)
{
Application.Run(
new Eventdemo());
}
}
Note: If you're using Visual Studio or another IDE, remember to add references to System.Drawing.dll and System.Windows.Forms.dll before compiling Listing 14.2 or just add the code to a Windows Forms project. Teaching the operation of Visual Studio or other IDE's is out-of-scope for this tutorial.
You may have noticed that Listing 14-2 is a Windows Forms program. Although I haven't covered Windows Forms in this tutorial, you should know enough about C# programming in general that you won't be lost. To help out, I'll give a brief explanation of some of the parts that you may not be familiar with.
The Eventdemo class inherits Form, which essentially makes it a Windows Form. This automatically gives you all the functionality of a Windows Form, including Title Bar, Minimize/Maximize/Close buttons, System Menu, and Borders. A lot of power, that inheritance thing, eh?
The way a Windows Form's application is started is by calling the Run() method of the staticApplication object with a reference to the form object as its parameter. This starts up all the underlying Windows plumbing, displays the GUI, and ensures that events are fired as appropriate.
Let's look at the custom event first. Below is the event declaration, which is a member of the Eventdemo class. It is declared with the event keyword, a delegate type, and an eventname.
public event Startdelegate StartEvent;
Anyone interested in an event can register by hooking up a delegate for that event. On the next line, we have a delegate of type Startdelegate, which the event was declared to accept, hooked up to the StartEvent event. The += syntax registers a delegate with anevent. To unregister with an event, use the -= with the same syntax.
StartEvent += new Startdelegate(OnStartEvent);
Firing an event looks just like a method call, as shown below:
StartEvent();
This was how to implement events from scratch, declaring the event and delegate yourself. However, much of the event programming you'll do will be with pre-defined events anddelegates. This leads us to the other event code you see in Listing 14-2, where we hook up an EventHandler delegate to a Button Click event.
clickMe.Click += new EventHandler(OnClickMeClicked);
The Click event already belongs to the Button class and all we have to do is reference it when registering a delegate. Similarly, the EventHandler delegate already exists in theSystem namespace of the .NET Frameworks Class Library. All you really need to do is define your callback method (delegate handler method) that is invoked when someone presses theclickMe button. The OnClickMeClicked() method, shown below, conforms to the signature of the EventHander delegate, which you can look up in the .NET Framework Class Library reference.
public void OnClickMeClicked(object sender, EventArgs ea)
{
MessageBox.Show("You Clicked My Button!");
}
Any time the clickMe button is pressed with a mouse, it will fire the Click event, which will invoke the OnClickMeClicked() method. The Button class takes care of firing the Click eventand there's nothing more you have to do. Because it is so easy to use pre-defined eventsand delegates, it would be a good idea to check if some exist already that will do what you need, before creating your own.

C Sharp Tutorials/Lesson 15 Lesson 15: Introduction to Exception Handling


This lesson teaches how to handle exceptions in your C# programs. Our objectives are as follows:
  • Learn what an exception is
  • Implement a routine with a try/catch block
  • Release resources in a finally block

Exceptions

Exceptions are unforeseen errors that happen in your programs. Most of the time, you can, and should, detect and handle program errors in your code. For example, validating user input, checking for null objects, and verifying the values returned from methods are what you expect, are all examples of good standard error handling that you should be doing all the time.
However, there are times when you don't know if an error will occur. For example, you can't predict when you'll receive a file I/O error, run out of system memory, or encounter a database error. These things are generally unlikely, but they could still happen and you want to be able to deal with them when they do occur. This is where exception handling comes in.
When exceptions occur, they are said to be "thrown". What is actually thrown is an object that is derived from the System.Exception class. In the next section, I'll be explaining how thrown exceptions are handled with try/catch blocks.
The System.Exception class provides several methods and properties for obtaining information on what went wrong. For example, the Message property provides summary information about what the error was, the Stacktrace property provides information from the stack for where the problem occurred, and the ToString() method is overridden to reveal a verbose description of the entire exception.
Identifying the exceptions you'll need to handle depends on the routine you're writing. For example, if the routine opened a file with the System.IO.File.OpenRead() method, it could throw any of the following exceptions:
  • SecurityException
  • ArgumentException
  • ArgumentNullException
  • PathTooLongException
  • DirectoryNotFoundException
  • UnauthorizedAccessException
  • FileNotFoundException
  • NotSupportedException
It's easy to find out what exceptions a method can raise by looking in the .NET Frameworks SDK Documentation. Just go to the Reference/Class Library section and look in the Namespace/Class/Method documentation for the methods you use. The exception in the list above were found by looking at the OpenRead() method definition of the File class in theSystem.IO namespace. Each exception identified has a hyperlink to its class definition that you can use to find out what that exception is about. Once you've figured out what exceptions can be generated in your code, you need to put the mechanisms in place to handle the exceptions, should they occur.

try/catch Blocks

When exceptions are thrown, you need to be able to handle them. This is done by implementing a try/catch block. Code that could throw an exception is put in the try block an exception handling code goes in the catch block. Listing 15-1 shows how to implement atry/catch block. Since an OpenRead() method could throw one of several exceptions, it is placed in the try block. If an exception is thrown, it will be caught in the catch block. The code in Listing 15-1 will print message and stack trace information out to the console if an exception is raised.
Note: The programs in this lesson cause exceptions on purpose. The exception that you see is generated intentionally to show you what the exception message looks like before you see it yourself in your own programs.
Listing 15-1. Using try/catch Blocks: tryCatchDemo.cs
using System;using System.IO;
class tryCatchDemo
{
static void Main(string[] args)
{
try{
File.OpenRead("NonExistentFile");
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
Although the code in Listing 15-1 only has a single catch block, all exceptions will be caught there because the type is of the base exception type "Exception". In exception handling, more specific exceptions will be caught before their more general parent exceptions. For example, the following snippet shows how to place multiple catch blocks:
catch(FileNotFoundException fnfex)
{
Console.WriteLine(fnfex.ToString());
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString());
}
If the file doesn't exist, a FileNotFoundException exception will be thrown and caught by the first catch block. However, if a PathTooLongException exception was raised, the second catch part would catch the exception. This is because there isn't a catch block for thePathTooLongException exception and the generic Exception type catch block is the only option available to catch the exception.
Exceptions that are not handled will normally bubble up the stack until a calling routine in the call chain handles them. If you forget to include try/catch blocks in a part of your code and there aren't any try/catch blocks earlier in the call chain, your program will abort with a message describing the exception. To your users this would be very cryptic and uncomfortable. It is good practice to provide exception handling in your programs.

Finally Blocks

An exception can leave your program in an inconsistent state by not releasing resources or doing some other type of cleanup. A catch block is a good place to figure out what may have gone wrong and try to recover, however it can't account for all scenarios. Sometimes you need to perform clean up actions whether or not your program succeeds. These situations are good candidates for using a finally block.
Listing 15-2 illustrates the usefulness of a finally block. As you know, a file stream must be closed when you're done with it. In this case, the file stream is the resource that needs to be cleaned up. In Listing 15-2, outStream is opened successfully, meaning the program now has a handle to an open file resource. When trying to open the inStream, aFileNotFoundException exception is raised, causing control to go immediately to the catchblock.
It's possible to close the outStream in the catch block, but what if the algorithm executed successfully without an exception? On success, the file would never be closed. Fortunately, we've included a finally block in Listing 15-2, which will always be executed. That's right, regardless of whether the algorithm in the try block raises an exception or not, the code in the finally block will be executed before control leaves the method.
Listing 15-2. Implementing a finally Block: FinallyDemo.cs
using System;using System.IO;
class FinallyDemo
{
static void Main(string[] args)
{
FileStream outStream = 
null;
FileStream inStream = 
null;
try
{
outStream = File.OpenWrite("DestinationFile.txt");
inStream = File.OpenRead("BogusInputFile.txt");
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString());
}
finally{if (outStream != null)
{
outStream.Close();
Console.WriteLine("outStream closed.");
}
if (inStream != null)
{
inStream.Close();
Console.WriteLine("inStream closed.");
}
}
}
}
A finally block is not required and you may ask what happens if you just put code after the catch block. True, under normal circumstances, if the exception is caught, all code following the catch will be executed. However, try/catch/finally is for exceptional circumstances and it is better to plan for the worst to make your program more robust. For example, if one of the catch handlers rethrew an exception or caused another exception, the code following the catch block (not in a finally block) would never be executed. Also, if you don't catch the exception at all, program flow would immediately do a stack walk looking for an exception handler that fits and the code following the catch blocks would not be executed. Since there is too much potential for code in an algorithm to not be executed, a finally block is your insurance for executing those critical actions you need.

C Sharp Tutorials/Lesson 16 Lesson 16: Using Attributes


This lesson explains how to use C# attributes. Our objectives are as follows:
  • Understand what attributes are and why they're used
  • Apply various attributes with multiple or no parameters
  • Use assembly, type member, and type level attributes

Why Attributes?

Attributes are elements that allow you to add declarative information to your programs. This declarative information is used for various purposes during runtime and can be used at design time by application development tools. For example, there are attributes such as DllImportAttribute that allow a program to communicate with the Win32 libraries. Another attribute, ObsoleteAttribute, causes a compile-time warning to appear, letting the developer know that a method should no longer be used. When building Windows forms applications, there are several attributes that allow visual components to be drag-n-dropped onto a visual form builder and have their information appear in the properties grid. Attributes are also used extensively in securing .NET assemblies, forcing calling code to be evaluated against pre-defined security constraints. These are just a few descriptions of how attributes are used in C# programs.
The reason attributes are necessary is because many of the services they provide would be very difficult to accomplish with normal code. You see, attributes add what is called metadata to your programs. When your C# program is compiled, it creates a file called an assembly, which is normally an executable or DLL library. Assemblies are self-describing because they have metadata written to them when they are compiled. Via a process known as reflection, a program's attributes can be retrieved from its assembly metadata. Attributes are classes that can be written in C# and used to decorate your code with declarative information. This is a very powerful concept because it means that you can extend your language by creating customized declarative syntax with attributes.
This tutorial will show how to use pre-existing attributes in C# programs. Understanding the concepts and how to use a few attributes, will help in finding the multitude of other pre-existing attributes in the .NET class libraries and use them also.

Attribute Basics

Attributes are generally applied physically in front of type and type member declarations. They're declared with square brackets, "[" and "]", surrounding the attribute such as the following ObsoleteAttribute attribute:
[ObsoleteAttribute]
The "Attribute" part of the attribute name is optional. So the following is equivalent to the attribute above:
[Obsolete]
You'll notice that the attribute is declared with only the name of the attribute, surrounded by square brackets. Many attributes have parameter lists, that allow inclusion of additional information that customizes a program even further. Listing 16.1 shows various ways of how to use the ObsoleteAttribute attribute.
Listing 16-1. How to Use Attributes: BasicAttributeDemo.cs
using System;
class BasicAttributeDemo
{
[Obsolete]
public void MyFirstdeprecatedMethod()
{
Console.WriteLine("Called MyFirstdeprecatedMethod().");
}

[ObsoleteAttribute]
public void MySecondDeprecatedMethod()
{
Console.WriteLine("Called MySecondDeprecatedMethod().");
}

[Obsolete("You shouldn't use this method anymore.")]
public void MyThirdDeprecatedMethod()
{
Console.WriteLine("Called MyThirdDeprecatedMethod().");
}
// make the program thread safe for COM[STAThread]static void Main(string[] args)
{
BasicAttributeDemo attrDemo = 
new BasicAttributeDemo();

attrDemo.MyFirstdeprecatedMethod();
attrDemo.MySecondDeprecatedMethod();
attrDemo.MyThirdDeprecatedMethod();
}
}
Examining the code in listing 16-1 reveals that the ObsoleteAttribute attribute was used a few different ways. The first usage appeared on the MyFirstdeprecatedMethod() method and the second usage appeared in the MySecondDeprecatedMethod() method as follows:
[Obsolete]public void MyFirstdeprecatedMethod()
...
[ObsoleteAttribute]
public void MySecondDeprecatedMethod()
...
The only difference between the two attributes is that MySecondDeprecatedMethod()method contains the "Attribute" in the attribute declaration. The results of both attributes are exactly the same. Attributes may also have parameters, as shown in the following declaration:
[Obsolete("You shouldn't use this method anymore.")]public void MyThirdDeprecatedMethod()
...
This adds customized behavior to the ObsoleteAttribute attribute which produces different results from the other ObsoleteAttribute attribute declarations. The results of all threeObsoleteAttribute attributes are shown below. These are the warnings that are emitted by the C# compiler when the program is compiled:
>csc BasicAttributeDemo.cs
Microsoft (R) Visual C# .NET Compiler version 7.10.2292.4
for Microsoft (R) .NET Framework version 1.1.4322
Copyright (C) Microsoft Corporation 2001-2002. All rights reserved.

BasicAttributeDemo.cs(29,3): warning CS0612:
'BasicAttributeDemo.MyFirstdeprecatedMethod()' is obsolete
BasicAttributeDemo.cs(30,3): warning CS0612:
'BasicAttributeDemo.MySecondDeprecatedMethod()' is obsolete
BasicAttributeDemo.cs(31,3): warning CS0618:
'BasicAttributeDemo.MyThirdDeprecatedMethod()' is obsolete: 'You
shouldn't use this method anymore.' 
As you can see, the ObsoleteAttribute attribute caused the MyThirdDeprecatedMethod()method to emit the message that was a parameter to the ObsoleteAttribute attribute of that method in the code. The other attributes simply emitted standard warnings.
Listing 16-1 also contains another attribute you're likely to see, the STAThreadAttributeattribute. You'll often see this attribute applied to the Main() method, indicating that this C# program should communicate with unmanaged COM code using the Single Threading Apartment . It is generally safe to use this attribute all the time because you never know when a 3rd party library you're using is going to be communicating with COM. The following excerpt shows how to use the STAThreadAttribute attribute:
[STAThread]static void Main(string[] args)
...

Attribute Parameters

Attributes often have parameters that enable customization. There are two types of parameters that can be used on attributes, positional and named. Positional parameters are used when the attribute creator wishes the parameters to be required. However, this is not a hard and fast rule because the ObsoleteAttribute attribute has a second positional parameter named error of type bool that we can omit as demonstrated in Listing 16-1. That attribute could have been written with the second positional parameter to force a compiler error instead of just a warning as follows:
[Obsolete("You shouldn't use this method anymore.", true)]public void MyThirdDeprecatedMethod()
...
The difference between positional parameters and named parameters are that named parameters are specified with the name of the parameter and are always optional. TheDllImportAttribute attribute is one you are likely to see that has both positional and named attributes (Listing 16-2).
Listing 16-2. Using Positional and Named Attribute Parameters: AttributeParamsDemo.cs
using System;using System.Runtime.InteropServices;
class AttributeParamsDemo
{
[DllImport("User32.dll", EntryPoint="MessageBox")]
static extern int MessageDialog(int hWnd, string msg, string caption, int msgType);

[STAThread]
static void Main(string[] args)
{
MessageDialog(0, "MessageDialog Called!", "DllImport Demo", 0);
}
}
The DllImportAttribute attribute in Listing 16-2 has one positional parameter, "User32.dll", and one named parameter, EntryPoint="MessageBox". Positional parameters are always specified before any named parameters. When there are named parameters, they may appear in any order. This is because they are marked with the parameter name like in theDllImportAttribute attribute, EntryPoint="MessageBox". Since the purpose of this lesson is to explain how to use attributes in general, I won't go into the details of theDllImportAttribute attribute, which has extra parameters that require knowledge of Win32 and other details that don't pertain to this lesson. Many other attributes can be used with both positional and named parameters.

Attribute Targets

The attributes shown so far have been applied to methods, but there are many other C# language elements that you can use attributes with. table 16-1 outlines the C# language elements that attributes may be applied to. They are formally called attribute "targets".
Attribute TargetCan be Applied To
alleverything
assemblyentire assembly
classclasses
constructorconstructors
delegatedelegates
enumenums
eventevents
fieldfields
interfaceinterfaces
methodmethods
modulemodules (compiled code that can be part of an assembly)
parameterparameters
propertyproperties
returnvaluereturn values
structstructures
Whenever there is ambiguity in how an attribute is applied, you can add a target specification to ensure the right language element is decorated properly. An attribute that helps ensure assemblies adhere to the Common Language Specification (CLS) is theCLSCompliantAttribute attribute. The CLS is the set of standards that enable different .NET languages to communicate. Attribute targets are specified by prefixing the attribute name with the target and separating it with a colon (:). Listing 16-3 shows how to use theCLSCompliantAttribute attribute and apply it to the entire assembly.
Listing 16-3. Using Positional and Named Attribute Parameters: AttributeTargetdemo.cs
using System;

[assembly:CLSCompliant(
true)]
public
 class AttributeTargetdemo
{
public void NonClsCompliantMethod(uint nclsParam)
{
Console.WriteLine("Called NonClsCompliantMethod().");
}

[STAThread]
static void Main(string[] args)
{
uint myUint = 0;

AttributeTargetdemo tgtdemo = 
new AttributeTargetdemo();

tgtdemo.NonClsCompliantMethod(myUint);
}
}
The code in Listing 16-3 will generate a compiler warning because of the uint type parameter declared on the NonClsCompliantMethod() method. If you change theCLSCompliantAttribute attribute to false or change the type of theNonClsCompliantMethod() method to a CLS compliant type, such as int, the program will compile without warnings.
The point about Listing 16-3 is that the CLSCompliantAttribute attribute is decorated with an attribute target of "assembly". This causes all members of this assembly to be evaluated according to the CLSCompliantAttribute attribute setting. To limit the scope of theCLSCompliantAttribute, apply it to either the AttributeTargetdemo class orNonClsCompliantMethod() method directly.