Wednesday, November 16, 2011

Connecting to Database


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.

Creating a SqlConnection Object

A SqlConnection is an object, just like any other C# object.  Most of the time, you just declare and instantiate the SqlConnection all at the same time, as shown below:
    SqlConnection conn = new SqlConnection(
        "Data Source=(local);Initial Catalog=Northwind;Integrated Security=SSPI");
The SqlConnection object instantiated above uses a constructor with a single argument of type string This argument is called a connection string. Table 1 describes common parts of a connection string.
Table 1. ADO.NET Connection Strings contain certain key/value pairs for specifying how to make a database connection. They include the location, name of the database, and security credentials.
Connection String Parameter NameDescription
Data SourceIdentifies the server. Could be local machine, machine domain name, or IP Address.
Initial CatalogDatabase name.
Integrated SecuritySet to SSPI to make connection with user's Windows login
User IDName of user configured in SQL Server.
PasswordPassword matching SQL Server User ID.
Integrated Security is secure when you are on a single machine doing development. However, you will often want to specify security based on a SQL Server User ID with permissions set specifically for the application you are using. The following shows a connection string, using the User ID and Password parameters:
    SqlConnection conn = new SqlConnection(
        "Data Source=DatabaseServer;Initial Catalog=Northwind;User ID=YourUserID;Password=YourPassword");
Notice how the Data Source is set to DatabaseServer to indicate that you can identify a database located on a different machine, over a LAN, or over the Internet. Additionally, User ID and Password replace the Integrated Security parameter.

Using a SqlConnection

The purpose of creating a SqlConnection object is so you can enable other ADO.NET code to work with a database. Other ADO.NET objects, such as a SqlCommand and a SqlDataAdapter take a connection object as a parameter. The sequence of operations occurring in the lifetime of a SqlConnection are as follows:
  1. Instantiate the SqlConnection.
  2. Open the connection.
  3. Pass the connection to other ADO.NET objects.
  4. Perform database operations with the other ADO.NET objects.
  5. Close the connection.
We've already seen how to instantiate a SqlConnection. The rest of the steps, opening, passing, using, and closing are shown in Listing 1.
Listing 1. Using a SqlConnection
using System;using System.Data;using System.Data.SqlClient;/// <summary>
///
 Demonstrates how to work with SqlConnection objects/// </summary>class SqlConnectionDemo
{
    static void Main()
    {
        // 1. Instantiate the connection        SqlConnection conn = new SqlConnection(
            
"Data Source=(local);Initial Catalog=Northwind;Integrated Security=SSPI");

        SqlDataReader rdr = 
null;
        try
        {            // 2. Open the connection            conn.Open();
            // 3. Pass the connection to a command object
            SqlCommand cmd = new SqlCommand("select * from Customers", conn);
            //
            // 4. Use the connection
            //

            // get query results
            rdr = cmd.ExecuteReader();
            // print the CustomerID of each record
            while (rdr.Read())
            {
                
Console.WriteLine(rdr[0]);
            }
        }        finally        {            // close the reader            if (rdr != null)
            {
                rdr.Close();
            }

            // 5. Close the connection
            if (conn != null)
            {
                conn.Close();
            }
        }
    }
}

As shown in Listing 1, you open a connection by calling the Open() method of the SqlConnection instance, conn. Any operations on a connection that was not yet opened will generate an exception. So, you must open the connection before using it.
Before using a SqlCommand, you must let the ADO.NET code know which connection it needs. In Listing 1, we set the second parameter to theSqlCommand object with the SqlConnection object, conn. Any operations performed with the SqlCommand will use that connection.
The code that uses the connection is a SqlCommand object, which performs a query on the Customers table. The result set is returned as aSqlDataReader and the while loop reads the first column from each row of the result set, which is the CustomerID column. We'll discuss theSqlCommand and SqlDataReader objects in later lessons. For right now, it is important for you to understand that these objects are using theSqlConnection object so they know what database to interact with.
When you are done using the connection object, you must close it. Failure to do so could have serious consequences in the performance and scalability of your application. There are a couple points to be made about how we closed the connection in Listing 1: the Close() method is called in a finally block and we ensure that the connection is not null before closing it.
Notice that we wrapped the ADO.NET code in a try/finally block. finally blocks help guarantee that a certain piece of code will be executed, regardless of whether or not an exception is generated. Since connections are scarce system resources, you will want to make sure they are closed in finally blocks.
Another precaution you should take when closing connections is to make sure the connection object is not null. If something goes wrong when instantiating the connection, it will be null and you want to make sure you don't try to close an invalid connection, which would generate an exception.
This example showed how to use a SqlConnection object with a SqlDataReader, which required explicitly closing the connection. However, when using a disconnected data model, you don't have to open and close the connection yourself. We'll see how this works in a future lesson when we look at the SqlDataAdapter object.

Summary

SqlConnection objects let other ADO.NET code know what database to connect to and how to make the connection. They are instantiated by passing a connection string with a set of key/value pairs that define the connection. The steps you use to manage the lifetime of a connection are create, open, pass, use, and close. Be sure to close your connection properly when you are done with it to ensure you don't have a connection resource leak.

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/

Data Providers

We know that ADO.NET allows us to interact with different types of data sources and different types of databases. However, there isn't a single set of classes that allow you to accomplish this universally. Since different data sources expose different protocols, we need a way to communicate with the right data source using the right protocol Some older data sources use the ODBC protocol, many newer data sources use the OleDb protocol, and there are more data sources every day that allow you to communicate with them directly through .NET ADO.NET class libraries.
ADO.NET provides a relatively common way to interact with data sources, but comes in different sets of libraries for each way you can talk to a data source. These libraries are called Data Providers and are usually named for the protocol or data source type they allow you to interact with. Table 1 lists some well known data providers, the API prefix they use, and the type of data source they allow you to interact with.
Table 1. ADO.NET Data Providers are class libraries that allow a common way to interact with specific data sources or protocols. The library APIs have prefixes that indicate which provider they support.
Provider NameAPI prefixData Source Description
ODBC Data ProviderOdbcData Sources with an ODBC interface. Normally older data bases.
OleDb Data ProviderOleDbData Sources that expose an OleDb interface, i.e. Access or Excel.
Oracle Data ProviderOracleFor Oracle Databases.
SQL Data ProviderSqlFor interacting with Microsoft SQL Server.
Borland Data ProviderBdpGeneric access to many databases such as Interbase, SQL Server, IBM DB2, and Oracle.
An example may help you to understand the meaning of the API prefix. One of the first ADO.NET objects you'll learn about is the connection object, which allows you to establish a connection to a data source. If we were using the OleDb Data Provider to connect to a data source that exposes an OleDb interface, we would use a connection object named OleDbConnection. Similarly, the connection object name would be prefixed with Odbc or Sql for an OdbcConnection object on an Odbc data source or a SqlConnection object on a SQL Server database, respectively. Since we are using MSDE in this tutorial (a scaled down version of SQL Server) all the API objects will have the Sql prefix. i.e. SqlConnection.

ADO.NET Objects

ADO.NET includes many objects you can use to work with data. This section introduces some of the primary objects you will use. Over the course of this tutorial, you'll be exposed to many more ADO.NET objects from the perspective of how they are used in a particular lesson. The objects below are the ones you must know. Learning about them will give you an idea of the types of things you can do with data when using ADO.NET.
The SqlConnection Object
To interact with a database, you must have a connection to it. The connection helps identify the database server, the database name, user name, password, and other parameters that are required for connecting to the data base. A connection object is used by command objects so they will know which database to execute the command on.
The SqlCommand Object
The process of interacting with a database means that you must specify the actions you want to occur. This is done with a command object. You use a command object to send SQL statements to the database. A command object uses a connection object to figure out which database to communicate with. You can use a command object alone, to execute a command directly, or assign a reference to a command object to an SqlDataAdapter, which holds a set of commands that work on a group of data as described below.
The SqlDataReader Object
Many data operations require that you only get a stream of data for reading. The data reader object allows you to obtain the results of a SELECT statement from a command object. For performance reasons, the data returned from a data reader is a fast forward-only stream of data. This means that you can only pull the data from the stream in a sequential manner This is good for speed, but if you need to manipulate data, then a DataSet is a better object to work with.
The DataSet Object
DataSet objects are in-memory representations of data. They contain multiple Datatable objects, which contain columns and rows, just like normal database tables. You can even define relations between tables to create parent-child relationships. The DataSet is specifically designed to help manage data in memory and to support disconnected operations on data, when such a scenario make sense. The DataSet is an object that is used by all of the Data Providers, which is why it does not have a Data Provider specific prefix.
The SqlDataAdapter Object
Sometimes the data you work with is primarily read-only and you rarely need to make changes to the underlying data source Some situations also call for caching data in memory to minimize the number of database calls for data that does not change. The data adapter makes it easy for you to accomplish these things by helping to manage data in a disconnected mode. The data adapter fills a DataSet object when reading the data and writes in a single batch when persisting changes back to the database. A data adapter contains a reference to the connection object and opens and closes the connection automatically when reading from or writing to the database. Additionally, the data adapter contains command object references for SELECT, INSERT, UPDATE, and DELETE operations on the data. You will have a data adapter defined for each table in a DataSet and it will take care of all communication with the database for you. All you need to do is tell the data adapter when to load from or write to the database.

Summary

ADO.NET is the .NET technology for interacting with data sources. You have several Data Providers, which allow communication with different data sources, depending on the protocols they use or what the database is. Regardless, of which Data Provider used, you'll use a similar set of objects to interact with a data source. The SqlConnection object lets you manage a connection to a data source. SqlCommand objects allow you to talk to a data source and send commands to it. To have fast forward-only read access to data, use the SqlDataReader. If you want to work with disconnected data, use a DataSet and implement reading and writing to/from the data source with a SqlDataAdapter.

C# File Handling


File data needs to be processed in nearly every non-trivial program, and the classes in the base class library that you can use have lots of details. With these benchmarks and examples focused on file IO in the C# language, we evaluate file handling.
One of the most significant sources of inefficiency is unnecessary input/output (I/O).McConnell, p. 598

StreamReader/StreamWriter

Two of the most useful types for handling files in the C# language and .NET Framework are the StreamReader and StreamWriter types; they are described here. Often, you can achieve better performance with StreamReader and StreamWriter than with static File methods.
Program that uses ReadLine [C#]

using System.IO;

class Program
{
    static void Main()
    {
 // Read in every line in the file.
 using (StreamReader reader = new StreamReader("file.txt"))
 {
     string line;
     while ((line = reader.ReadLine()) != null)
     {
  // Do something with line
  string[] parts = line.Split(',');
     }
 }
    }
}

Result
    Lines in text file are read in and separated on commas.

File.ReadAllText

This simple program uses the File.ReadAllText method to load in the file "file.txt" on the C: volume. Then, it prints the contents of the file, which are now stored in a string object.
System.IO namespace [C#]

//
// Include this namespace for all the examples.
//
using System.IO;

Program that reads in file [C#]

using System;
using System.IO;

class Program
{
    static void Main()
    {
 string file = File.ReadAllText("C:\\file.txt");
 Console.WriteLine(file);
    }
}

Output

File contents.
File.ReadAllText benchmark. Here we want to resolve whether File.ReadAllText is efficient. To answer this, the ReadAllText method was benchmarked against StreamReader. The result was that on a 4 KB file it was almost 40% slower.
Program that uses ReadAllText and StreamReader [C#]

using System.IO;

class Program
{
    static void Main()
    {
 // Read in file with File class.
 string text1 = File.ReadAllText("file.txt");

 // Alternative: use custom StreamReader method.
 string text2 = FileTools.ReadFileString("file.txt");
    }
}

public static class FileTools
{
    public static string ReadFileString(string path)
    {
 // Use StreamReader to consume the entire text file.
 using (StreamReader reader = new StreamReader(path))
 {
     return reader.ReadToEnd();
 }
    }
}

Benchmark results

File.ReadAllText:         155 ms
FileTools.ReadFileString: 109 ms
StreamReader helper. In some projects, it would be worthwhile to use the above ReadFileString custom static method. In a project that opens hundreds of small files, it would save 0.1 milliseconds per file.

File.ReadAllLines

Here you want to read all the lines in from a file and place them in an array. The following code reads in each line in the file "file.txt" into an array. This is efficient code; we provide performance information later on.
Program that uses ReadAllLines [C#]

using System.IO;

class Program
{
    static void Main()
    {
 // Read in every line in specified file.
 // ... This will store all lines in an array in memory,
 // ... which you may not want or need.
 string[] lines = File.ReadAllLines("file.txt");
 foreach (string line in lines)
 {
     // Do something with line
     if (line.Length > 80)
     {
  // Example code
     }
 }
    }
}

Result
    We loop over lines in the file.
    We test the length of each line.
File.ReadAllLines performance. When you read in a file with File.ReadAllLines, many strings are allocated and put into an array in a single method call. With StreamReader, however, you can allocate each string as you pass over the file by calling ReadLine. This makes StreamReader more efficient unless you need all the file data in memory at once.

Read into List. We look at a usage of the List constructed type with file handling methods. List and ArrayList are extremely useful data structures for C# programmers, as they allow object collections to rapidly expand or shrink. Here we look at how you can use LINQ to get a List of lines from a file in one line.
Program that uses ReadAllLines with List [C#]

using System.Collections.Generic;
using System.IO;
using System.Linq;

class Program
{
    static void Main()
    {
 // Read in all lines in the file,
 // ... and then convert to a List with LINQ.
 List<string> fileLines = File.ReadAllLines("file.txt").ToList();
    }
}
Count lines. Here we need to count the number of lines in a file but don't want to write lots of code to do it. Note that the example here doesn't have ideal performance characteristics. We reference the Length property on the array returned.
Program that counts lines [C#]

using System.IO;

class Program
{
    static void Main()
    {
 // Another method of counting lines in a file.
 // ... This is not the most efficient way.
 // ... It counts empty lines.
 int lineCount = File.ReadAllLines("file.txt").Length;
    }
}
Query example. Does a line containing a specific string exist in the file? Maybe you want to see if a name or location exists in a line in the file. Here we can harness the power of LINQ to find any matching line. See also the Contains method on the List type.
Program that uses LINQ on file [C#]

using System.IO;
using System.Linq;

class Program
{
    static void Main()
    {
 // One way to see if a certain string is a line
 // ... in the specified file. Uses LINQ to count elements
 // ... (matching lines), and then sets |exists| to true
 // ... if more than 0 matches were found.
 bool exists = (from line in File.ReadAllLines("file.txt")
         where line == "Some line match"
         select line).Count() > 0;
    }
}

File.ReadLines

In constrast to File.ReadAllLines, File.ReadLines does not read in every line immediately upon calling it. Instead, it reads lines only as they are needed. It is best used in a foreach-loop.

File.WriteAllLines

Here we look at how you can write an array to a file. When you are done with your in-memory processing, you often need to write the data to disk. Fortunately, the File class offers an excellent WriteAllLines method. It receives the file path and then the array to write. This will replace all the file contents.
Program that writes array to file [C#]

using System.IO;

class Program
{
    static void Main()
    {
 // Write a string array to a file.
 string[] stringArray = new string[]
 {
     "cat",
     "dog",
     "arrow"
 };
 File.WriteAllLines("file.txt", stringArray);
    }
}

Output

cat
dog
arrow

File.WriteAllText

A very simple method to call, the File.WriteAllText method receives two arguments: the path of the output file, and the exact string contents of the text file. If you need to create a simple text file, this is an ideal method.
Program that uses File.WriteAllText [C#]

using System.IO;

class Program
{
    static void Main()
    {
 File.WriteAllText("C:\\perls.txt",
     "Dot Net Perls");
    }
}

Output
    C:\perls.txt contains the string "Dot Net Perls"

File.AppendAllText

Here we mention a way you can append text to files in a simple method. The previous example will replace the file's contents, but for a log file or error listing, we must append to the file. Note that we could read in the file, append to that in memory, and then write it out completely again, but that's slow.

File.AppendText

The File.AppendText method returns a StreamWriter instance that you can use to append string data to the specified file. It is not covered on this site in detail because it is usually easier to use the StreamWriter constructor directly.

File.ReadAllBytes

Here we use File.ReadAllBytes to read in an image, PNG, to memory. One example usage of this sample is to cache an image in memory for performance. This works very well and greatly outperforms reading in the image each time.
Program that caches binary file [C#]

static class ImageCache
{
    static byte[] _logoBytes;
    public static byte[] Logo
    {
 get
 {
     // Returns logo image bytes.
     if (_logoBytes == null)
     {
  _logoBytes = File.ReadAllBytes("Logo.png");
     }
     return _logoBytes;
 }
    }
}

Forms Event Handler and Handling the events


No GUI application is complete without enabling actions. Even though arranging components is a significant issue, applying actions is also equally important. These actions are what instructs the program to act when something happens.  For example, Mouse clicks, Keyboard presses, etc. Before beginning our discussion let's review how different API’s handle events.
Microsoft Foundation Classes (MFC): These classes are based upon Microsoft's Win32 API. Normally development work is done through Visual C++.  
Java API: Here, the majority of work is done by employing AWT and Swing packages. Actions are enabled by applying Interfaces. The main difficulty is that you should learn and remember all methods in the corresponding interfaces.  Otherwise, you receive compile time errors.
As compared to the above, Event handling in C# is much more simplified. It's possible to handle various Mouse and Key related events quickly and in a more efficient manner. Learning will be easier, if you understand the basic principles behind handling events, which are elaborated below 
  1. Invoke the related event by supplying a custom method or event handler using the += operator as shown here:
b1.Click += new EventHandler(OnClick);
  1. Apply the event handler as described below. It must be in conformance with a delegate of the class System.EventHandler:
          public delegate void EventHandler(object sender, Event args)
The first argument indicates the object sending the event and the second argument contains information for the current event. You can use this argument object to handle functions associated with the related event. Listing - 1 below illustrates how to print ”Hello C#” inside a Textbox when a Button is clicked:

Listing – 1

using System;
using System.Windows.forms;
using System.Drawing;

public class Butevent:form  {

        TextBox t1 = new TextBox();
        Button b1 = new Button();

        public Butevent() {

            this.Text = "Program developed by Anand.N";

            t1.Location = new Point(20,30);

            b1.Text = "Click here to activate";
            b1.Location = new Point(20,55);
            b1.Size = new Size(150,20);

            
// Invoking Method or EventHandler
           
b1.Click+=new EventHandler(OnClick);

           this.Controls.Add(t1);
           this.Controls.Add(b1);

            
// Invoking Method or EventHandler
          
 this.Resize += new EventHandler(OnResize);
    }

   
  //Applying EventHandler
    public void OnResize(object sender,EventArgs ee) {

        MessageBox.Show("oops! form Resized");

    }


     //Applying EventHandler
    
public void OnClick(object sender,EventArgs e)   {

        t1.Text = "Hello C#";

    }

    public static void Main() {

        Application.Run(new Butevent());

    }
}
The above example also shows how to handle a Resize event. try resizing the forms border and observe the result.

Handling MouseEvents

You can handle various Mouse actions by using the events specified in the Control class. The following listing shows how to handle a simple MouseUp Event:

Listing – 2

using System;
using System.Windows.forms;
using System.Drawing;

public class Mousedemo:form  {

    public Mousedemo()  {

        this.MouseUp += new MouseEventHandler(OnMouseup);

    }

    public void OnMouseup(object sender,MouseEventArgs e)   {

        this.Text = "Current Position (" +e.X + " , " + e.Y +")";

    }

    public static void Main()  {

         Application.Run(new Mousedemo());

    }
}
try out the above example and observe the result.  Click, DoubleClick, MouseEnter, and  MouseLeave events can be handled in a similar way.

Using KeyBoard Events

Every modern programming language contains all necessary functions for handling KeyBoard related events. C# also provides us with three events Keypress, KeyUp and KeyDown, which you can use to handle Keyboard events. Listing – 3, below, shows the usage of the KeyUp Event. Copy the code given below, compile, and observe the output.

Listing – 3

using System;
using System.Windows.forms;
using System.Drawing;
public class Keydemo:form {

    public Keydemo() {

        this.KeyUp += new KeyEventHandler(OnKeypress);
    }

    public void OnKeypress(object sender, KeyEventArgs e)    {

        MessageBox.Show(e.KeyCode.ToString(), "Your input");

    }

    public static void Main()    {

        Application.Run(new Keydemo());
    }
}

Generics


You already have 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?

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]);
    }
The first thing you should notice is the generic collection List<int>, which is referred to as List of int. If you looked in the documentation for this class, you would find that it is defined as List<T>, where T could be any type. For example, if you wanted the list to work on string or Customerobjects, you could define them as List<string> or List<Customer> and they would hold only string or Customer objects. In the example above,myInts holds only type int.
Using the Add method, you can add as many int objects to the collection as you want. This is different from arrays, which have a fixed size. The List<T> class has many more methods you can use, such as ContainsRemove, and more.
There are two parts of the for loop that you need to know about. First, the condition uses the Count property of myInts. This is another difference between collections and arrays in that an array uses a Length property for the same thing. Next, the way to read from a specific position in the List<T> collection, myInts[i], is the exact same syntax you use with arrays.
The next time you start to use a single-dimension array, consider using a List<T> instead. That said, be sure to let your solution fit the problem and use the best tool for the job. i.e. it's common to work with byte[] in many places in the .NET Framework.

Working with Dictionary<TKey, TValue> Collections

Another very useful generic collection is the Dictionary, which works with key/value pairs. There is a non-generic collection, called a Hashtablethat does the same thing, except that it operates on type object. However, as explained earlier in this lesson, you want to avoid the non-generic collections and use thier generic counterparts instead. The scenario I'll use for this example is that you have a list of Customers that you need to work with. It would be natural to keep track of these Customers via their CustomerID. The Dictionary example will work with instances of the following Customer class:
    public class Customer
    {
        public Customer(int id, string name)
        {
            ID = id;
            Name = name;
        }

        private int m_id;

        public int ID
        {
            get { return m_id; }
            set { m_id = value; }
        }

        private string m_name;

        public string Name
        {
            get { return m_name; }
            set { m_name = value; }
        }
    }
The Customer class above has a constructor to make it easier to initialize. It also exposes its state via public properties. It isn't very sophisticated at this point, but that's okay because its only purpose is to help you learn how to use a Dictionary collection.  The following example populates a Dictionary collection with Customer objects and then shows you how to extract entries from the Dictionary:
     Dictionary<int, Customer> customers = new Dictionary<int, Customer>();

    Customer cust1 = new Customer(1, "Cust 1");
    Customer cust2 = new Customer(2, "Cust 2");
    Customer cust3 = new Customer(3, "Cust 3");

    customers.Add(cust1.ID, cust1);
    customers.Add(cust2.ID, cust2);
    customers.Add(cust3.ID, cust3);

    foreach (KeyValuePair<int, Customer> custKeyVal in customers)
    {
        Console.WriteLine(
            "Customer ID: {0}, Name: {1}",
            custKeyVal.Key,
            custKeyVal.Value.Name);
    }
The customers variable is declared as a Dictionary<int, Customer>.  Considering that the formal declaration of Dictionary is Dictionary<TKey, TValue>, the meaning of customers is that it is a Dictionary where the key is type int and the value is type Customer. Therefore, any time you add an entry to the Dictionary, you must provide the key because it is also the key that you will use to extract a specified Customer from theDictionary.
I created three Customer objects, giving each an ID and a Name. I'll use the ID as the key and the entire Customer object as the value. You can see this in the calls to Add, where custX.ID is added as the key (first parameter) and the custX instance is added as the value (second parameter).
Extracting information from a Dictionary is a little bit different. Iterating through the customers Dictionary with a foreach loop, the type returned is KeyValuePair<TKey, TValue>, where TKey is type int and TValue is type Customer because those are the types that the customers Dictionaryis defined with.
Since custKeyVal is type KeyValuePair<int, Customer> it has Key and Value properties for you to read from. In our example, custKeyVal.Key will hold the ID for the Customer instance and custKeyVal.Value will hold the whole Customer instance. The parameters in the Console.WriteLinestatement demonstrate this by printing out the ID, obtained through the Key property, and the Name, obtained through the Name property of the Customer instance that is returned by the Value property.
The Dictionary type is handy for those situations where you need to keep track of objects via some unique identifier. For your convenience, here's Listing 20-1, shows how both the List and Dictionary collections work.
Listing 20-1. Introduction to Using Generic Collections with an Example of the List<T> and Dictionary<TKey, TValue> Generic Collections
using System;
using System.Collections.Generic;

public class Customer
{
    public Customer(int id, string name)
    {
        ID = id;
        Name = name;
    }

    private int m_id;

    public int ID
    {
        get { return m_id; }
        set { m_id = value; }
    }

    private string m_name;

    public string Name
    {
        get { return m_name; }
        set { m_name = value; }
    }
}

class Program
{
    static void Main(string[] args)
    {
        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]);
        }

        Dictionary<int, Customer> customers = new Dictionary<int, Customer>();

        Customer cust1 = new Customer(1, "Cust 1");
        Customer cust2 = new Customer(2, "Cust 2");
        Customer cust3 = new Customer(3, "Cust 3");

        customers.Add(cust1.ID, cust1);
        customers.Add(cust2.ID, cust2);
        customers.Add(cust3.ID, cust3);

        foreach (KeyValuePair<int, Customer> custKeyVal in customers)
        {
            Console.WriteLine(
                "Customer ID: {0}, Name: {1}",
                custKeyVal.Key,
                custKeyVal.Value.Name);
        }

        Console.ReadKey();
    }
}
Whenever coding with the generic collections, add a using System.Collections.Generic declaration to your file, just as in Listing 20-1.

Summary

Generic collections give you the best of all worlds with the strong typing of arrays and flexibility of non-generic collections. There are many more generic collections to choose from also, such as StackQueue, and SortedDictionary. Look in the System.Collections.Generic namespace for other generic collections.

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

Summary

This has been an introduction to handling exceptions. By now, you should have a good understanding of what an exception is. You can implement algorithms within try/catch blocks that handle exceptions. Additionally, you know how to clean up resources by implementing afinally block whose code is always executed before leaving a method.