Total Pageviews

Tuesday, September 25, 2012

Interfaces


Interfaces

An interface looks like a class, but has no implementation. The only thing it contains are declarations of eventsindexersmethods and/orproperties. The reason interfaces only provide declarations is because they are inherited by classes and structs, which must provide an implementation for each interface member declared.
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 theIDisposable interface, it is making a statement that it guarantees it has the Dispose() method, which is the only member of the IDisposableinterface. Any code that wishes to use class foo may check to see if class foo implements IDisposable. When the answer is true, then the code knows that it can call foo.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". Thisinterface has a single method named MethodToImplement(). 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 a void 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 interfacecould 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 IMyInterfaceinterface. 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.");
    }
}

Delegates and Events


                 Delegates and 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.
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 an if/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 aboutdelegates, we'll apply a delegate 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 instantiation
        
Comparer cmp = new Comparer(Name.CompareFirstNames);

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

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

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

        sd.PrintNames();
    }

    // observe  the delegate parameter    public 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 delegateDelegate declarations look somewhat like methods, except they have thedelegate 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 this delegate 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 type object, and return anint 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 FirstName properties 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 delegatecmp, 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 the event 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 delegate may 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 theevent 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 event    public 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 event        StartEvent();
    }

    // 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 fired    public void OnStartEvent()
    {
        MessageBox.Show("I Just Started!");
    }

    static
 void Main(string[] args)
    {
        Application.Run(
new Eventdemo());
    }
}

Enums


                   Enums

Enums:

Enums are strongly typed constants. They are essentially unique types that allow you to assign symbolic names to integral values. In the C# tradition, they are strongly typed, meaning that an enum of one type may not be implicitly assigned to an enum of another type even though the underlying value of their members are the same. Along the same lines, integral types and enums are not implicitly interchangable. All assignments between different enum types and integral types require an explicit cast.
Enums lend themselves to more maintainable code because they are symbolic, allowing you to work with integral values, but using a meaningful name to do so. For example, what type of code would you rather work with - a set of values named North, South, East, and West or the set of integers 0, 1, 2, and 3 that mapped to the same values, respectively? Enums make working with strongly typed constants via symbolic names easy.
Enums are value types, which means they contain their own value, can't inherit or be inherited from, and assignment copies the value of one enum to another. You will see in this lesson and elsewhere that enums are used and referred to with both lower case, enum, and upper case,Enum. The relationship between the two is that the C# type, enum, inherits the Base Class Library (BCL) type, Enum. Use the C# type, enum, to define new enums and use the BCL type, Enum, to implement static enum methods.

Creating an Enum

The .NET Framework Class Library contains many enums and examples of how they are used. For example, every time you put an icon on aMessageBox, you use the MessageBoxIcon enum. For a list of available enums in the .NET Framework Class Library, look at the documentation for the Enum class and click on the Derived Classes link.
Whenever there are situations where you are using a set of related numbers in a program, consider replacing those numbers with enums. It will make a program more readable and type safe. Listing 17-1 contains an enum definition and code that uses that enum in a switchstatement. Instead of using the numbers 0, 1, and 2 in the switch statement, the code is more meaningful through the use of the Volumeenum.
Listing 17-1. Creating and Using an Enum: EnumSwitch.cs
using System;// declares the enumpublic enum Volume
{
   Low,   Medium,
   High
}

// demonstrates how to use the enum

class
 EnumSwitch
{
   static void Main()
   {
      // create and initialize       // instance of enum type
      Volume myVolume = Volume.Medium;

      // make decision based
      // on enum value      switch (myVolume)
      {
         case Volume.Low:
            Console.WriteLine("The volume has been turned Down.");
            break;         case Volume.Medium:
            Console.WriteLine("The volume is in the middle.");
            break;         case Volume.High:
            Console.WriteLine("The volume has been turned up.");
            break;
      }
      Console.ReadLine();
   }
}
Listing 17-1 contains a definition for an enum. Notice that it is declared with the enum keyword, has a type identifier (Volume), and contains a comma separated list of values enclosed within curly braces.
This enum is of type Volume and we use it to declare the myVolume variable in the Main method. Since an enum is a value type, we can assign a value (Volume.Medium) to it directly, similar to the simple types such as int or double. Once the myVolume variable is declared and initialized, it is used in the switch statement.Each of the case statements represent a unique member of the Volume enum.
Any time a member of the Volume enum is used, it is fully qualified with the "Volume" identifier to guarantee type safety. For example, if there were a Meat enum in scope, then Meat.Medium would definitely have different semantics than Volume.Medium. With both enums in scope, it would be ambiguous to just use the Medium identifier without type qualification. Using the type identifier ensures such mistakes are not made.

Using Enums

An enum is typically specified as shown in Listing 17-1, but may be customized by changing its base type and member values. By default, the underlying type of an enum is int. This default may be changed by specifying a specific base when declaring the enum. You would specify a different base if the enum was used extensively and there was an opportunity for space savings by selecting a smaller type. Another reason may be if you wanted the underlying type of the enum to correspond to another type in your program and you wanted to explicitly cast between the two without loss of precision. Valid base types include bytesbyteshortushortintuintlong, and ulong.
Another modification you can make to an enum is to set the value of any enum member. By default, the first member of an enum takes the value of zero. If this value doesn't make sense for your enum, you can change it to one or some other number. Additionally, you can change any of the members of an enum to any value that is valid for its base type. Unassigned enum members have a value that is one more than their predecessor. Listing 17-2 shows how to modify the base type and member values of an enum.
Listing 17-2. Setting the Enum Base and Initializing Members: EnumBaseAndMembers.cs
using System;// declares the enumpublic enum Volume : byte{
    Low = 1,
    Medium,
    High
}
class EnumBaseAndMembers
{
    static void Main()
    {
        // create and initialize
        // instance of enum type
        Volume myVolume = Volume.Low;
        // make decision based
        // on enum value
        switch (myVolume)
        {
            case Volume.Low:
                Console.WriteLine("The volume has been turned Down.");
                break;            case Volume.Medium:
                Console.WriteLine("The volume is in the middle.");
                break;            case Volume.High:
                Console.WriteLine("The volume has been turned up.");
                break;
        }
        Console.ReadLine();
    }
}
The Volume enum in Listing 17-2 shows how to modify the base type and members of an enum.Its base type is changed to byte with the : <type> syntax following the enum identifier, Volume.This ensures that the Volume enum may only have members with values that are valid for type byte.
The first member of the Volume enum, Low, has its value changed to 1. The same syntax, <member> = <value>, may be applied to any member of the enum. You are restricted from creating forward references, circular references, and duplicate references in enum members.
The default values of the Volume enum are Low=0, Medium=1, and High=2 because the first member of an enum defaults to 0 and the following members default to one more than their predecessor. However, the Volume enum in Listing 17-2 has its Low member set to 1, which means that Medium=2 and High=3.

Enum tricks

Enum types implicitly inherit the System.Enum type in the Base Class Library (BCL). This also means that you can use the members of System.Enum to operate on enum types. This section does just that, showing some useful tips and tricks to use with enums in your programs.
A common requirement with enums is to convert between the enum and a variable of its base type. For example, if you are getting input in the form of an int from a user or a file stream, then you can cast it to an enum and use it in a meaningful way in your program. You can also get a complete list of enum member names or enum values, which is useful if you have logic that needs to iterate through every enum member. Listing 17-3 shows how to perform conversions between enums and their base types and how to use some of the System.Enum type members.
Listing 17-3. Enum Conversions and using the System.Enum Type: Enumtricks.cs
using System;// declares the enumpublic enum Volume : byte{
    Low = 1,
    Medium,
    High
}


// shows different ways
// to work with enums
class Enumtricks
{
    static void Main(string[] args)
    {
        // instantiate type        Enumtricks enumtricks = new Enumtricks();        // demonstrates explicit cast
        // of int to Volume
        enumtricks.GetEnumFromUser();
        // iterate through Volume enum by name
        enumtricks.ListEnumMembersByName();        // iterate through Volume enum by value        enumtricks.ListEnumMembersByValue();

        Console.ReadLine();
    }
    // demonstrates explicit cast
    // of int to Volume
    public void GetEnumFromUser()
    {
        Console.WriteLine("\n----------------");
        Console.WriteLine("Volume Settings:");
        Console.WriteLine("----------------\n");

        Console.Write(@"
1 - Low
2 - Medium
3 - High

Please select one (1, 2, or 3): ");
        // get value user provided        string volString = Console.ReadLine();        int volInt = Int32.Parse(volString);        // perform explicit cast from
        // int to Volume enum type
        Volume myVolume = (Volume)volInt;

        Console.WriteLine();

        // make decision based
        // on enum value
        switch (myVolume)
        {
            case Volume.Low:
                Console.WriteLine("The volume has been turned Down.");
                break;            case Volume.Medium:
                Console.WriteLine("The volume is in the middle.");
                break;            case Volume.High:
                Console.WriteLine("The volume has been turned up.");
                break;
        }

        Console.WriteLine();
    }

    // iterate through Volume enum by name
    public void ListEnumMembersByName()
    {
        Console.WriteLine("\n---------------------------- ");
        Console.WriteLine("Volume Enum Members by Name:");
        Console.WriteLine("----------------------------\n");

        // get a list of member names from Volume enum,
        // figure out the numeric value, and display
        foreach (string volume in Enum.GetNames(typeof(Volume)))
        {
            Console.WriteLine("Volume Member: {0}\n Value: {1}",
                volume, (
byte)Enum.Parse(typeof(Volume), volume));
        }
    }

    // iterate through Volume enum by value
    public void ListEnumMembersByValue()
    {
        Console.WriteLine("\n----------------------------- ");
        Console.WriteLine("Volume Enum Members by Value:");
        Console.WriteLine("-----------------------------\n");
        // get all values (numeric values) from the Volume
        // enum type, figure out member name, and display
        foreach (byte val in Enum.GetValues(typeof(Volume)))
        {
            Console.WriteLine("Volume Value: {0}\n Member: {1}",
                val, Enum.GetName(
typeof(Volume), val));
        }
    }
}
The code in Listing 17-3 includes three method calls to GetEnumFromUserListEnumMembersByName, and ListEnumMembersByValue. Each of these methods demonstrate a different aspect of using System.Enum to work with enums.
The GetEnumFromUser method shows how to obtain int input and translate it to an appropriate enum type. Converting an int to an enum makes the code more readable and type safe. The following is an excerpt from Listing 17-3 that shows the pertinent part of the code that performs the conversion:
        // get value user provided        string volString = Console.ReadLine();        int volInt = Int32.Parse(volString);        // perform explicit cast from
        // int to Volume enum type
        Volume myVolume = (Volume)volInt;
After the program displays a menu, it prompts the user for a selection in the form of a number (1, 2, or 3). When the user makes a selection and presses the Enter key, the code reads the value with Console.ReadLine, which returns the value as a string type. Since you can only cast an int to a Volume enum type, the user's input must be converted from a string to an int with the Int32.Parse method. Converting the int to aVolume enum type is simply a matter of applying a cast operation during assignment.
To get all the members of an enum at the same time, you can use the GetNames method of the System.Enum type, which returns a stringarray of the names of all an enum's members. An excerpt from the ListEnumMembersByName method in Listing 17.3 that shows this appears below:
        // get a list of member names from Volume enum,
        // figure out the numeric value, and display
        foreach (string volume in Enum.GetNames(typeof(Volume)))
        {
            Console.WriteLine("Volume Member: {0}\n Value: {1}",
                volume, (
byte)Enum.Parse(typeof(Volume), volume));
        }
Because GetNames returns an array of strings, it is easy to use in a loop statement such as foreach. Something you may be curious about in the code above is the second parameter to the WriteLine method's format string. Given the enum type and a string representation of the member name, you can use the Enum.Parse method to get the underlying value of that member. Because the Volume enum's base type is byte, the return value from Enum.Parse must be cast to a byte before assignment, forcing the numeric representation of the enum value to appear. If we would have omitted the byte cast, the output would be the Volume enum member, which would then be converted to a string representation of the member name, which is not what the code intended to show.
Instead of getting names of all the members of an enum, you may have a reason to get all the values of the enum at one time. The code below, from the ListEnumMembersByValue method in Listing 17.3, shows how to accomplish this:
        // get all values (numeric values) from the Volume
        // enum type, figure out member name, and display
        foreach (byte val in Enum.GetValues(typeof(Volume)))
        {
            Console.WriteLine("Volume Value: {0}\n Member: {1}",
                val, Enum.GetName(
typeof(Volume), val));
        }
Given the type of the enum, the GetValues method of System.Enum will return an array of the given enum's base type, which in this case isbyte. While iterating through this list, each member is printed to the console showing its value and name. The name is obtained by using theGetName method of System.Enum, which accepts an enum type and value for which to get the corresponding name of.

Enums are lists of strongly typed constants with members that are symbolic names, corresponding to an underlying integral type. Enum base types can be changed and member values can be specified. The System.Enum .NET Framework Class Library type is the base class of enum types and contains methods that allow you to work with enums in different ways, such as working with a list of names or values, converting from value to name, and converting from name to value. For more information on the System.Enum type, see the .NET Framework SDK 

Overloading Operators


                           Overloading Operators




To understand the need for operator overloading, imagine that you need to perform matrix math operations in your program. You could instantiate a couple 2-dimensional arrays and do what you need. However, add the requirement for the matrix behavior to be reusable. Because you need to do the same thing in other programs and want to take advantage of the fact that you have already written the code, you will want to create a new type.
So, you create a Matrix type, which could be a class or a struct. Now consider how this Matrix type would be used. You would want to initialize two or more Matrix instances with data and then do a mathematical operation with them, such as add or get a dot product. To accomplish the mathematical operation, you could implement an Add()DotProduct(), and other methods to get the job done. Using the classes would look something like this:
Matrix result = mat1.Add(mat2);  // instance
or
Matrix result = Matrix.Add(mat1, mat2);  // static
or even worse
Matrix result = mat1.DotProduct(mat2).DotProduct(mat3); // and so on...
The problem with using methods like this is that it is cumbersome, verbose, and unnatural for the problem you are trying to solve. It would be much easier to have a + operator for the add operation and a * operator for the dot product operation. The following shows how the syntax appears using operators:
Matrix result = mat1 + mat2;
or
Matrix result = mat1 * mat2;
or even better
Matrix result = mat1 * mat2 * mat3 * mat4;
This is much more elegant and easier to work with. For a single operation, one could argue that the amount of work to implement one syntax over the other is not that great. However, when chaining multiple mathematical operations, the syntax is much simpler. Additionally, if the primary users of your type are mathematicians and scientists, operators are more intuitive and natural.

When Not to Use Operator Overloading

A lot of the discussion, so far, has emphasized the need to write code and implement types in the simplest and most natural way possible. A very important concept to remember is that although operators are simple, they are not always natural. In the example above it made sense to use operators with the Matrix type. This is similar to the reason why operators make sense with the built-in types such as int and float. However, it is easy to abuse operators and create convoluted implementations that are hard for anyone, including the original author, to understand.
For an example of a bad implementation, consider a Car class that needs an implementation allowing you to park the car in a garage. It would be a mistake to think that the following implementation was smart:
Car mySedan = new Car();
Garage parkingGarage = new Garage();

mySedan = mySedan + parkingGarage; // park car in the garage
This is bad code. If you ever have the temptation to do something like this - don't. No one will truly understand what it means and they will not think it is clever. Furthermore, it hurts the maintainability of the application because it is so hard to understand what the code does. Although the comment is there, it doesn't help much and if it wasn't there, it would be even more difficult to grasp the concept of adding a Carand a Garage.
The idea is this: Use operators where they lend understanding and simplicity to a type. Otherwise, do not use them.

Implementing an Overloaded Operator

The syntax required to implement an overloaded operator is much the same as a static method with a couple exceptions. You must use theoperator keyword and specify the operator symbol being overloaded. Here's a skeleton example of how the dot product operator could be implemented:
public static Matrix operator *(Matrix mat1, Matrix mat2)
{
    // dot product implementation
}
Notice that the method is static. Use the keyword operator after specifying the return type, Matrix in this case. Following the operator keyword, the actual operator symbol is specified and then there is a set of parameters to be operated on. See Listing 18-1 for a full example of how to implement and use an overloaded operator.
Listing 18-1. Implementing an Overloaded Operator: Matrix.cs
using System;

class Matrix
{
 public const int DimSize = 3;
 private double[,] m_matrix = new double[DimSize, DimSize];

 // allow callers to initialize
 public double this[int x, int y]
 {
  get { return m_matrix[x, y]; }
  set { m_matrix[x, y] = value; }
 }

 // let user add matrices
 public static Matrix operator +(Matrix mat1, Matrix mat2)
 {
  Matrix newMatrix = new Matrix();

  for (int x=0; x < DimSize; x++)
   for (int y=0; y < DimSize; y++)
    newMatrix[x, y] = mat1[x, y] + mat2[x, y];

  return newMatrix;
 }
}

class MatrixTest
{
 // used in the InitMatrix method.
 public static Random m_rand = new Random();

 // test Matrix
 static void Main()
 {
  Matrix mat1 = new Matrix();
  Matrix mat2 = new Matrix();

  // init matrices with random values
  InitMatrix(mat1);
  InitMatrix(mat2);
  
  // print out matrices
  Console.WriteLine("Matrix 1: ");
  PrintMatrix(mat1);

  Console.WriteLine("Matrix 2: ");
  PrintMatrix(mat2);

  // perform operation and print out
            results
  Matrix mat3 = mat1 + mat2;

  Console.WriteLine();
  Console.WriteLine("Matrix 1 + Matrix
            2 = ");
  PrintMatrix(mat3);

  Console.ReadLine();
 }

 // initialize matrix with random values
 public static void InitMatrix(Matrix mat)
 {
  for (int x=0; x < Matrix.DimSize; x++)
   for (int y=0; y < Matrix.DimSize; y++)
    mat[x, y] = m_rand.NextDouble();
 }

 // print matrix to console
 public static void PrintMatrix(Matrix mat)
 {
  Console.WriteLine();
  for (int x=0; x < Matrix.DimSize; x++)
  {
   Console.Write("[ ");
   for (int y=0; y < Matrix.DimSize; y++)
   {
    // format the output
    Console.Write("{0,8:#.000000}", mat[x, y]);

    if ((y+1 % 2) < 3)
     Console.Write(", ");
   }
   Console.WriteLine(" ]");
  }
  Console.WriteLine();
 }
}
Similar to the skeleton example of the dot product operator, the Matrix class in Listing 18-1 contains an operator overload for the + operator. For your convenience, I've extracted the pertinent overload implementation in the code below:
 // let user add matrices
 public static Matrix operator +(Matrix mat1, Matrix mat2)
 {
  Matrix newMatrix = new Matrix();

  for (int x=0; x < DimSize; x++)
   for (int y=0; y < DimSize; y++)
    newMatrix[x, y] = mat1[x, y] + mat2[x, y];

  return newMatrix;
 }
The operator is static, which is the only way it can and should be declared because an operator belongs to the type and not a particular instance. There are just a few rules you have to follow when implementing operator overloads. What designates this as an operator is the use of the keyword operator, followed by the + symbol. The parameter types are both of the enclosing type, Matrix. The implementation of the operator overload creates a new instance of the return type and performs a matrix add.

Operator Rules

C# enforces certain rules when you overload operators. One rule is that you must implement the operator overload in the type that will use it. This is sensible because it makes the type self-contained.
Another rule is that you must implement matching operators. For example, if you overload ==, you must also implement !=. The same goes for <= and >=.
When you implement an operator, its compound operator works also. For example, since the + operator for the Matrix type was implemented, you can also use the += operator on Matrix types.

Exceptions Handling


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 Messageproperty 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 theSystem.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 the System.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 and exception handling code goes in the catch block. Listing 15-1 shows how to implement a try/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 aPathTooLongException 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 includetry/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, a FileNotFoundException exception is raised, causing control to go immediately to the catch block.
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.