Tuesday 27 December 2011

Lesson 07: Using Stored Procedures

This lesson shows how to use stored procedures in your data access code. Here are the objectives of this lesson:

  • Learn how to modify the SqlCommand object to use a stored procedure.
  • Understand how to use parameters with stored procedures.

Introduction

A stored procedures is a pre-defined, reusable routine that is stored in a database. SQL Server compiles stored procedures, which makes them more efficient to use. Therefore, rather than dynamically building queries in your code, you can take advantage of the reuse and performance benefits of stored procedures. The following sections will show you how to modify the SqlCommand object to use stored procedures. Additionally, you'll see another reason why parameter support is an important part of the ADO.NET libraries.

Lesson 06: Adding Parameters to Commands

This lesson shows you how to use parameters in your commands.2 Here are the objectives of this lesson:
  • Understand what a parameter is.
  • Be informed about the benefits of using parameters.
  • Learn how to create a parameter.
  • Learn how to assign parameters to commands.

Introduction

When working with data, you'll often want to filter results based on some criteria. Typically, this is done by accepting input from a user and using that input to form a SQL query. For example, a sales person may need to see all orders between specific dates. Another query might be to filter customers by city.
As you know, the SQL query assigned to a SqlCommand object is simply a string. So, if you want to filter a query, you could build the string dynamically, but you wouldn't want to. Here is a bad example of filtering a query.
 // don't ever do this
 SqlCommand cmd = new SqlCommand(
  "select * from Customers where city = '" + inputCity + "'";
Don't ever build a query this way! The input variable, inputCity, is typically retrieved from a TextBox control on either a Windows form or a Web Page. Anything placed into that TextBox control will be put into inputCity and added to your SQL string. This situation invites a hacker to replace that string with something malicious. In the worst case, you could give full control of your computer away.
Instead of dynamically building a string, as shown in the bad example above, use parameters. Anything placed into a parameter will be treated as field data, not part of the SQL statement, which makes your application much more secure.

Lesson 05: Working with Disconnected Data - The DataSet and SqlDataAdapter

This lesson explains how to work with disconnected data, using the DataSet and SqlDataAdapter objects. Here are the objectives of this lesson:
  • Understand the need for disconnected data.
  • Obtain a basic understanding of what a DataSet is for.
  • Learn to use a SqlDataAdapter to retrieve and update data.

Introduction

In Lesson 3, we discussed a fully connected mode of operation for interacting with a data source by using the SqlCommand object. In Lesson 4, we learned about how to read data quickly an let go of the connection with the SqlDataReader. This Lesson shows how to accomplish something in-between SqlConnection and SqlDataReader interaction by using the DataSet and SqlDataAdapter objects.
A DataSet is an in-memory data store that can hold numerous tables. DataSets only hold data and do not interact with a data source. It is the SqlDataAdapter that manages connections with the data source and gives us disconnected behavior. The SqlDataAdapter opens a connection only when required and closes it as soon as it has performed its task. For example, the SqlDataAdapter performs the following tasks when filling a DataSet with data:
  1. Open connection
  2. Retrieve data into DataSet
  3. Close connection
and performs the following actions when updating data source with DataSet changes:
  1. Open connection
  2. Write changes from DataSet to data source
  3. Close connection
In between the Fill and Update operations, data source connections are closed and you are free to read and write data with the DataSet as you need. These are the mechanics of working with disconnected data. Because the applications holds on to connections only when necessary, the application becomes more scalable.

Lesson 04: Reading Data with the SqlDataReader

This lesson explains how to read data with a SqlDataReader object. Here are the objectives of this lesson:
  • Learn what a SqlDataReader is used for.
  • Know how to read data using a SqlDataReader.
  • Understand the need to close a SqlDataReader.

Introduction

A SqlDataReader is a type that is good for reading data in the most efficient manner possible. You can *not* use it for writing data. SqlDataReaders are often described as fast-forward firehose-like streams of data.
You can read from SqlDataReader objects in a forward-only sequential manner. Once you've read some data, you must save it because you will not be able to go back and read it again.
The forward only design of the SqlDataReader is what enables it to be fast. It doesn't have overhead associated with traversing the data or writing it back to the data source. Therefore, if your only requirement for a group of data is for reading one time and you want the fastest method possible, the SqlDataReader is the best choice. Also, if the amount of data you need to read is larger than what you would prefer to hold in memory beyond a single call, then the streaming behavior of the SqlDataReader would be a good choice.
Note: Observe that I used the term "one time" in the previous paragraph when discussing the reasons why you would use a SqlDataReader. As with anything, there are exceptions. In many cases, it is more efficient to use a cached DataSet. While caching is outside the scope of this tutorial, we will discuss using DataSet objects in the next lesson.

Creating a SqlDataReader Object

Getting an instance of a SqlDataReader is a little different than the way you instantiate other ADO.NET objects. You must call ExecuteReader on a command object, like this:
    SqlDataReader rdr = cmd.ExecuteReader();
The ExecuteReader method of the SqlCommand object, cmd , returns a SqlDataReader instance. Creating a SqlDataReader with the new operator doesn't do anything for you. As you learned in previous lessons, the SqlCommand object references the connection and the SQL statement necessary for the SqlDataReader to obtain data.

Lesson 03: The SqlCommand Object

This lesson describes the SqlCommand object and how you use it to interact with a database. Here are the objectives of this lesson:
  • Know what a command object is.
  • Learn how to use the ExecuteReader method to query data.
  • Learn how to use the ExecuteNonQuery method to insert and delete data.
  • Learn how to use the ExecuteScalar method to return a single value.

Introduction

A SqlCommand object allows you to specify what type of interaction you want to perform with a database. For example, you can do select, insert, modify, and delete commands on rows of data in a database table. The SqlCommand object can be used to support disconnected data management scenarios, but in this lesson we will only use the SqlCommand object alone. A later lesson on the SqlDataAdapter will explain how to implement an application that uses disconnected data. This lesson will also show you how to retrieve a single value from a database, such as the number of records in a table.

Creating a SqlCommand Object

Similar to other C# objects, you instantiate a SqlCommand object via the new instance declaration, as follows:
    SqlCommand cmd = new SqlCommand("select CategoryName from Categories", conn);
The line above is typical for instantiating a SqlCommand object. It takes a string parameter that holds the command you want to execute and a reference to a SqlConnection object. SqlCommand has a few overloads, which you will see in the examples of this tutorial.

Querying Data

When using a SQL select command, you retrieve a data set for viewing. To accomplish this with a SqlCommand object, you would use the ExecuteReader method, which returns a SqlDataReader object. We'll discuss the SqlDataReader in a future lesson. The example below shows how to use the SqlCommand object to obtain a SqlDataReader object:
// 1. Instantiate a new command with a query and connection
SqlCommand cmd =
new SqlCommand("select CategoryName from Categories", conn);

// 2. Call Execute reader to get query results
SqlDataReader rdr = cmd.ExecuteReader();

In the example above, we instantiate a SqlCommand object, passing the command string and connection object to the constructor. Then we obtain a SqlDataReader object by calling the ExecuteReader method of the SqlCommand object, cmd.
This code is part of the ReadData method of Listing 1 in the Putting it All Together section later in this lesson.

Lesson 02: The SqlConnection Object

This lesson describes the SqlConnection object and how to connect to a data base. Here are the objectives of this lesson:
  • Know what connection objects are used for.
  • Learn how to instantiate a SqlConnection object.
  • Understand how the SqlConnection object is used in applications.
  • Comprehend the importance of effective connection lifetime management.

Introduction

The first thing you will need to do when interacting with a data base is to create a connection. The connection tells the rest of the ADO.NET code which database it is talking to. It manages all of the low level logic associated with the specific database protocols. This makes it easy for you because the most work you will have to do in code is instantiate the connection object, open the connection, and then close the connection when you are done. Because of the way that other classes in ADO.NET are built, sometimes you don't even have to do that much work.
Although working with connections is very easy in ADO.NET, you need to understand connections in order to make the right decisions when coding your data access routines. Understand that a connection is a valuable resource. Sure, if you have a stand-alone client application that works on a single database one one machine, you probably don't care about this. However, think about an enterprise application where hundreds of users throughout a company are accessing the same database. Each connection represents overhead and there can only be a finite amount of them. To look at a more extreme case, consider a Web site that is being hit with hundreds of thousands of hits a day Applications that grab connections and don't let them go can have seriously negative impacts on performance and scalability.

Lesson 01: Introduction to ADO.NET

This lesson is an introduction to ADO.NET.  It introduces primary ADO.NET concepts and objects that you will learn about in later lessons.  Here are the objectives of this lesson:
  • Learn what ADO.NET is.
  • Understand what a data provider is.
  • Understand what a connection object is.
  • Understand what a command object is.
  • Understand what a DataReader object is.
  • Understand what a DataSet object is.
  • Understand what a DataAdapter object is.

Introduction

ADO.NET is an object-oriented set of libraries that allows you to interact with data sources. Commonly, the data source is a database, but it could also be a text file, an Excel spreadsheet, or an XML file. For the purposes of this tutorial, we will look at ADO.NET as a way to interact with a data base.
As you are probably aware, there are many different types of databases available. For example, there is Microsoft SQL Server, Microsoft Access, Oracle, Borland Interbase, and IBM DB2, just to name a few. To further refine the scope of this tutorial, all of the examples will use SQL Server.
You can download the Microsoft SQL Server 2000 Desktop Engine (MSDE 2000) here:
http://www.microsoft.com/sql/msde/downloads/download.asp
MSDE contains documentation on how to perform an installation. However, for your convenience, here are quick instructions on how to install MSDE:
http://www.asp.net/msde/default.aspx?tabindex=0&tabid=1
MSDE 2000 is a scaled down version of SQL Server. Therefore, everything you learn in this tutorial and all code will work with SQL Server. The examples will use the Northwind database. This is a tutorial is specifically for ADO.NET. MSDE is not part of ADO.NET, but it is one of the many data sources you can interact with by using ADO.NET If you need help with MSDE 2000, I refer you to the Microsoft Web site, where you can find pertinent information on licensing and technical assistance:
http://www.microsoft.com/sql/msde/

Lesson 23: Working with Nullable Types

Working with value types and data can sometimes be challenging because a value type doesn't normally hold a null value. This lesson shows you how to overcome this limitation with C# nullable types. Here's what you'll learn.
  • Understand the problem that nullable types solve
  • See how to declare a nullable type
  • Learn how to use nullable types

Understanding the Problem with Value Types and Null Values

As explained in Lesson 12: Structs, the default value of a struct (value type) is some form of 0. This is another difference between reference types and value types, in addition to what was described in Lesson 22: Topics on C# Type. The default value of a reference type is null. If you're just writing C# code and managing your own data source, such as a file that holds data for your application, the default values for structs works fine.

Lesson 22: Topics on C# Type

Throughout this tutorial, you've seen many different types, including those that are part of C# and custom designed types. If you've taken the samples and worked on them yourself, extending and writing your own programs, you are likely to have experienced errors associated with type. For example, you can't assign a double to an int without using a cast operator to perform the conversion. Another feature of C# concerns the semantic differences between reference and value types. Such problems should make you wonder why this is so and that's what this lesson is for. Here are the objectives for this lesson:
  • Understand the need for type safety
  • See how to convert one type to another
  • Learn about reference types
  • Learn about value types
  • Comprehend the semantic differences between reference and value types

Why Type Safety?

In untyped languages, such as scripting languages, you can assign one variable to another and the compiler/interpreter will use an intelligent algorithm to figure out how the assignment should be done. If the assignment is between two variables of the same type, all is good. However, if the assignment is between different types, you could have serious problems.
For example, if you assigned an int value to a float variable it would convert okay because the fractional part of the new float would just be zero. However, if you went the other way and assigned a float value to an int variable, that would most likely be a problem. You would lose all of the precision of the original float value. Consider the damage that could be caused if the float value represented a chemical ingredient, an engineering measurement, or a financial value. Finding such an error would be difficult and particularly expensive, especially if the error didn't show up until your application was in production (already being used by customers).

Using the Cast Operator for Conversions

In Lesson 02: Operators, Types, and Variables, you learned about C# types and operators. It explained the size and precision of the various types and there is a list of available operators. The cast operator, (x), is listed first as a primary operator in Table 2-4. When you must convert a type that doesn't fit, it must be done via what is called an explicit conversion, which uses the cast operator. Listing 22-1 has an example of an implicit conversion, which doesn't require the cast operator, and an explicit conversion.
Listing 22-1. Cast Operators

Lesson 21: Anonymous Methods

In Lesson 14: Introduction to Delegates, you learned about delegates and how they enable you to connect handlers to events. For C# v2.0, there is a new language feature, called anonymous methods, that are similar to delegates, but require less code. While you learn about anonymous methods, we'll cover the following objectives:
  • Understand the benefits of anonymous methods
  • Learn how to implement an anonymous method
  • Implement anonymous methods that use delegate parameters

How Do Anonymous Methods Benefit Me?

An anonymous method is a method without a name - which is why it is called anonymous. You don't declare anonymous methods like regular methods. Instead they get hooked up directly to events. You'll see a code example shortly.
To see the benefit of anonymous methods, you need to look at how they improve your development experience over using delegates. Think about all of the moving pieces there are with using delegates: you declare the delegate, write a method with a signature defined by the delegate interface, declare the event based on that delegate, and then write code to hook the handler method up to the delegate. With all this work to do, no wonder programmers, who are new to C# delegates, have to do a double-take to understand how they work.
Because you can hook an anonymous method up to an event directly, a couple of the steps of working with delegates can be removed. The next section shows you how this works.

Lesson 20: Introduction to Generic Collections

All the way back in Lesson 02, you learned about arrays and how they allow you to add and retrieve a collection of objects. Arrays are good for many tasks, but C# v2.0 introduced a new feature called generics. Among many benefits, one huge benefit is that generics allow us to create collections that allow us to do more than allowed by an array. This lesson will introduce you to generic collections and how they can be used. Here are the objectives for this lesson:
  • Understand how generic collections can benefit you
  • Learn how to create and use a generic List
  • Write code that implements a generic Dictionary

What Can Generics Do For Me?

Throughout this tutorial, you've learned about types, whether built-in (int, float, char) or custom (Shape, Customer, Account). In .NET v1.0 there were collections, such as the ArrayList for working with groups of objects. An ArrayList is much like an array, except it could automatically grow and offered many convenience methods that arrays don't have. The problem with ArrayList and all the other .NET v1.0 collections is that they operate on type object. Since all objects derive from the object type, you can assign anything to an ArrayList. The problem with this is that you incur performance overhead converting value type objects to and from the object type and a single ArrayList could accidentally hold different types, which would cause hard to find errors at runtime because you wrote code to work with one type. Generic collections fix these problems.
A generic collection is strongly typed (type safe), meaning that you can only put one type of object into it. This eliminates type mismatches at runtime. Another benefit of type safety is that performance is better with value type objects because they don't incur overhead of being converted to and from type object. With generic collections, you have the best of all worlds because they are strongly typed, like arrays, and you have the additional functionality, like ArrayList and other non-generic collections, without the problems.
The next section will show you how to use a generic List collection.

Creating Generic List<T> Collections

The pattern for using a generic List collection is similar to arrays. You declare the List, populate its members, then access the members. Here's a code example of how to use a List:
    List<int> myInts = new List<int>();

    myInts.Add(1);
    myInts.Add(2);
    myInts.Add(3);

    for (int i = 0; i < myInts.Count; i++)
    {
        Console.WriteLine("MyInts: {0}", myInts[i]);
    }

Lesson 19: Encapsulation

Earlier in this tutorial, you learned about two of the important principles of object-oriented programming, Inheritance and Polymorphism. Now that you've seen much of the syntax of C#, I'll show you how C# supports the another of the object-oriented principles - Encapsulation. This lesson will discuss Encapsulation with the following objectives:
  • Understand the object-oriented principle of Encapsulation.
  • Learn the available modifiers for type members.
  • Protect object state through properties.
  • Control access to methods.
  • Learn how to modify types for assembly encapsulation

What is Encapsulation and How Does It Benefit Me?

In object-oriented programming, you create objects that have state and behavior. An object's state is the data or information it contains. For example, if you have a BankAccount object, its state could be Amount and CustomerName. Behavior in an object is often represented by methods. For example, the BankAccount object's behavior could be Credit, Debit, and GetAmount. This sounds like a nice definition of an object, and it is, but you must also consider how this object will be used.
When designing an object, you must think about how others could use it. In a best-case scenario any program using the object would be well designed and the code would never change. However, the reality is that programs do change often and in a team environment many people touch the same code at one time or another. Therefore, it is beneficial to consider what could go wrong as well as the pristine image of how the object *should* be used.
In the case of the BankAccount object, examine the situation where code outside of your object could access a decimal Amount field or a string CustomerName field. At the point of time that the code is written, everything would work well. However, later in the development cycle, you realize that the BankAccount object should keep track of an int CustomerID rather than string CustomerName because you don't want to duplicate relationships between information (or some other valid reason to alter the definition of internal state). Such changes cause a rippling effect in your code because it was built to use the BankAccount class, as originally designed (with CustomerName being a string), and you must now change code that accesses that state throughout your entire application.
The object-oriented principle of Encapsulation helps avoid such problems, allowing you to hide internal state and abstract access to it though type members such as methods, properties, and indexers. Encapsulation helps you reduce coupling between objects and increases the maintainability of your code.

Lesson 18: Overloading Operators

This lesson shows you how to overload C# operators. Our objectives are as follows:
  • Understand what operator overloading is
  • Determine when it is appropriate to overload an operator
  • Learn how to overload an operator
  • Familiarize yourself with rules for operator overloading

About Operator Overloading

In Lesson 2, you learned what operators were available in C#, which included + (plus), - (minus), ^ (exclusive or), and others. Operators are defined for the built-in types, but that's not all. You can add operators to your own types, allowing them to be used much like the operators with the built-in C# types.
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.

Lesson 17: Enums

This lesson explains how to use C# enums. Our objectives are as follows:
  • Understand what an enum is
  • Be able to create new enum types
  • Learn how to use enums
  • Gain familiarity with System.Enum type methods

Enums Defined

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.

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.

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 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 about delegates, 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.

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 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.