- •Contents at a Glance
- •Table of Contents
- •Acknowledgments
- •Introduction
- •Who This Book Is For
- •Finding Your Best Starting Point in This Book
- •Conventions and Features in This Book
- •Conventions
- •Other Features
- •System Requirements
- •Code Samples
- •Installing the Code Samples
- •Using the Code Samples
- •Support for This Book
- •Questions and Comments
- •Beginning Programming with the Visual Studio 2008 Environment
- •Writing Your First Program
- •Using Namespaces
- •Creating a Graphical Application
- •Chapter 1 Quick Reference
- •Understanding Statements
- •Identifying Keywords
- •Using Variables
- •Naming Variables
- •Declaring Variables
- •Working with Primitive Data Types
- •Displaying Primitive Data Type Values
- •Using Arithmetic Operators
- •Operators and Types
- •Examining Arithmetic Operators
- •Controlling Precedence
- •Using Associativity to Evaluate Expressions
- •Associativity and the Assignment Operator
- •Incrementing and Decrementing Variables
- •Declaring Implicitly Typed Local Variables
- •Chapter 2 Quick Reference
- •Declaring Methods
- •Specifying the Method Declaration Syntax
- •Writing return Statements
- •Calling Methods
- •Specifying the Method Call Syntax
- •Applying Scope
- •Overloading Methods
- •Writing Methods
- •Chapter 3 Quick Reference
- •Declaring Boolean Variables
- •Using Boolean Operators
- •Understanding Equality and Relational Operators
- •Understanding Conditional Logical Operators
- •Summarizing Operator Precedence and Associativity
- •Using if Statements to Make Decisions
- •Understanding if Statement Syntax
- •Using Blocks to Group Statements
- •Cascading if Statements
- •Using switch Statements
- •Understanding switch Statement Syntax
- •Following the switch Statement Rules
- •Chapter 4 Quick Reference
- •Using Compound Assignment Operators
- •Writing while Statements
- •Writing for Statements
- •Understanding for Statement Scope
- •Writing do Statements
- •Chapter 5 Quick Reference
- •Coping with Errors
- •Trying Code and Catching Exceptions
- •Handling an Exception
- •Using Multiple catch Handlers
- •Catching Multiple Exceptions
- •Using Checked and Unchecked Integer Arithmetic
- •Writing Checked Statements
- •Writing Checked Expressions
- •Throwing Exceptions
- •Chapter 6 Quick Reference
- •The Purpose of Encapsulation
- •Controlling Accessibility
- •Working with Constructors
- •Overloading Constructors
- •Understanding static Methods and Data
- •Creating a Shared Field
- •Creating a static Field by Using the const Keyword
- •Chapter 7 Quick Reference
- •Copying Value Type Variables and Classes
- •Understanding Null Values and Nullable Types
- •Using Nullable Types
- •Understanding the Properties of Nullable Types
- •Using ref and out Parameters
- •Creating ref Parameters
- •Creating out Parameters
- •How Computer Memory Is Organized
- •Using the Stack and the Heap
- •The System.Object Class
- •Boxing
- •Unboxing
- •Casting Data Safely
- •The is Operator
- •The as Operator
- •Chapter 8 Quick Reference
- •Working with Enumerations
- •Declaring an Enumeration
- •Using an Enumeration
- •Choosing Enumeration Literal Values
- •Choosing an Enumeration’s Underlying Type
- •Working with Structures
- •Declaring a Structure
- •Understanding Structure and Class Differences
- •Declaring Structure Variables
- •Understanding Structure Initialization
- •Copying Structure Variables
- •Chapter 9 Quick Reference
- •What Is an Array?
- •Declaring Array Variables
- •Creating an Array Instance
- •Initializing Array Variables
- •Creating an Implicitly Typed Array
- •Accessing an Individual Array Element
- •Iterating Through an Array
- •Copying Arrays
- •What Are Collection Classes?
- •The ArrayList Collection Class
- •The Queue Collection Class
- •The Stack Collection Class
- •The Hashtable Collection Class
- •The SortedList Collection Class
- •Using Collection Initializers
- •Comparing Arrays and Collections
- •Using Collection Classes to Play Cards
- •Chapter 10 Quick Reference
- •Using Array Arguments
- •Declaring a params Array
- •Using params object[ ]
- •Using a params Array
- •Chapter 11 Quick Reference
- •What Is Inheritance?
- •Using Inheritance
- •Base Classes and Derived Classes
- •Calling Base Class Constructors
- •Assigning Classes
- •Declaring new Methods
- •Declaring Virtual Methods
- •Declaring override Methods
- •Understanding protected Access
- •Understanding Extension Methods
- •Chapter 12 Quick Reference
- •Understanding Interfaces
- •Interface Syntax
- •Interface Restrictions
- •Implementing an Interface
- •Referencing a Class Through Its Interface
- •Working with Multiple Interfaces
- •Abstract Classes
- •Abstract Methods
- •Sealed Classes
- •Sealed Methods
- •Implementing an Extensible Framework
- •Summarizing Keyword Combinations
- •Chapter 13 Quick Reference
- •The Life and Times of an Object
- •Writing Destructors
- •Why Use the Garbage Collector?
- •How Does the Garbage Collector Work?
- •Recommendations
- •Resource Management
- •Disposal Methods
- •Exception-Safe Disposal
- •The using Statement
- •Calling the Dispose Method from a Destructor
- •Making Code Exception-Safe
- •Chapter 14 Quick Reference
- •Implementing Encapsulation by Using Methods
- •What Are Properties?
- •Using Properties
- •Read-Only Properties
- •Write-Only Properties
- •Property Accessibility
- •Understanding the Property Restrictions
- •Declaring Interface Properties
- •Using Properties in a Windows Application
- •Generating Automatic Properties
- •Initializing Objects by Using Properties
- •Chapter 15 Quick Reference
- •What Is an Indexer?
- •An Example That Doesn’t Use Indexers
- •The Same Example Using Indexers
- •Understanding Indexer Accessors
- •Comparing Indexers and Arrays
- •Indexers in Interfaces
- •Using Indexers in a Windows Application
- •Chapter 16 Quick Reference
- •Declaring and Using Delegates
- •The Automated Factory Scenario
- •Implementing the Factory Without Using Delegates
- •Implementing the Factory by Using a Delegate
- •Using Delegates
- •Lambda Expressions and Delegates
- •Creating a Method Adapter
- •Using a Lambda Expression as an Adapter
- •The Form of Lambda Expressions
- •Declaring an Event
- •Subscribing to an Event
- •Unsubscribing from an Event
- •Raising an Event
- •Understanding WPF User Interface Events
- •Using Events
- •Chapter 17 Quick Reference
- •The Problem with objects
- •The Generics Solution
- •Generics vs. Generalized Classes
- •Generics and Constraints
- •Creating a Generic Class
- •The Theory of Binary Trees
- •Building a Binary Tree Class by Using Generics
- •Creating a Generic Method
- •Chapter 18 Quick Reference
- •Enumerating the Elements in a Collection
- •Manually Implementing an Enumerator
- •Implementing the IEnumerable Interface
- •Implementing an Enumerator by Using an Iterator
- •A Simple Iterator
- •Chapter 19 Quick Reference
- •What Is Language Integrated Query (LINQ)?
- •Using LINQ in a C# Application
- •Selecting Data
- •Filtering Data
- •Ordering, Grouping, and Aggregating Data
- •Joining Data
- •Using Query Operators
- •Querying Data in Tree<TItem> Objects
- •LINQ and Deferred Evaluation
- •Chapter 20 Quick Reference
- •Understanding Operators
- •Operator Constraints
- •Overloaded Operators
- •Creating Symmetric Operators
- •Understanding Compound Assignment
- •Declaring Increment and Decrement Operators
- •Implementing an Operator
- •Understanding Conversion Operators
- •Providing Built-In Conversions
- •Creating Symmetric Operators, Revisited
- •Adding an Implicit Conversion Operator
- •Chapter 21 Quick Reference
- •Creating a WPF Application
- •Creating a Windows Presentation Foundation Application
- •Adding Controls to the Form
- •Using WPF Controls
- •Changing Properties Dynamically
- •Handling Events in a WPF Form
- •Processing Events in Windows Forms
- •Chapter 22 Quick Reference
- •Menu Guidelines and Style
- •Menus and Menu Events
- •Creating a Menu
- •Handling Menu Events
- •Shortcut Menus
- •Creating Shortcut Menus
- •Windows Common Dialog Boxes
- •Using the SaveFileDialog Class
- •Chapter 23 Quick Reference
- •Validating Data
- •Strategies for Validating User Input
- •An Example—Customer Information Maintenance
- •Performing Validation by Using Data Binding
- •Changing the Point at Which Validation Occurs
- •Chapter 24 Quick Reference
- •Querying a Database by Using ADO.NET
- •The Northwind Database
- •Creating the Database
- •Using ADO.NET to Query Order Information
- •Querying a Database by Using DLINQ
- •Creating and Running a DLINQ Query
- •Deferred and Immediate Fetching
- •Joining Tables and Creating Relationships
- •Deferred and Immediate Fetching Revisited
- •Using DLINQ to Query Order Information
- •Chapter 25 Quick Reference
- •Using Data Binding with DLINQ
- •Using DLINQ to Modify Data
- •Updating Existing Data
- •Adding and Deleting Data
- •Chapter 26 Quick Reference
- •Understanding the Internet as an Infrastructure
- •Understanding Web Server Requests and Responses
- •Managing State
- •Understanding ASP.NET
- •Creating Web Applications with ASP.NET
- •Building an ASP.NET Application
- •Understanding Server Controls
- •Creating and Using a Theme
- •Chapter 27 Quick Reference
- •Comparing Server and Client Validations
- •Validating Data at the Web Server
- •Validating Data in the Web Browser
- •Implementing Client Validation
- •Chapter 28 Quick Reference
- •Managing Security
- •Understanding Forms-Based Security
- •Implementing Forms-Based Security
- •Querying and Displaying Data
- •Understanding the Web Forms GridView Control
- •Displaying Customer and Order History Information
- •Paging Data
- •Editing Data
- •Updating Rows Through a GridView Control
- •Navigating Between Forms
- •Chapter 29 Quick Reference
- •What Is a Web Service?
- •The Role of SOAP
- •What Is the Web Services Description Language?
- •Nonfunctional Requirements of Web Services
- •The Role of Windows Communication Foundation
- •Building a Web Service
- •Creating the ProductsService Web Service
- •Web Services, Clients, and Proxies
- •Talking SOAP: The Easy Way
- •Consuming the ProductsService Web Service
- •Chapter 30 Quick Reference
350 |
Part III Creating Components |
tree2.Insert(“Today”);
tree2.Insert(“I”);
tree2.Insert(“Hope”);
tree2.Insert(“You”);
tree2.Insert(“Are”);
tree2.Insert(“Feeling”);
tree2.Insert(“Well”);
tree2.Insert(“!”);
tree2.WalkTree();
}
These statements create another binary tree for holding strings, populate it with some test data, and then print the tree. This time, the data is sorted alphabetically.
11.On the Build menu, click Build Solution. Verify that the solution compiles, and correct any errors if necessary.
12.On the Debug menu, click Start Without Debugging.
The program runs and displays the integer values as before, followed by the strings in the following sequence:
!, Are, Are, Feeling, Hello, Hope, How, I, Today, Well, World, You, You
13.Press the Enter key to return to Visual Studio 2008.
Creating a Generic Method
As well as defining generic classes, you can also use the .NET Framework to create generic methods.
With a generic method, you can specify parameters and the return type by using a type parameter in a manner similar to that used when defining a generic class. In this way, you can define generalized methods that are type-safe and avoid the overhead of casting (and boxing in some cases). Generic methods are frequently used in conjunction with generic classes—you need them for methods that take a generic class as a parameter or that have a return type that is a generic class.
You define generic methods by using the same type parameter syntax that you use when
creating generic classes (you can also specify constraints). For example, you can call the following generic Swap<T> method to swap the values in its parameters. Because this func-
tionality is useful regardless of the type of data being swapped, it is helpful to define it as a generic method:
static void Swap<T>(ref T first, ref T second)
{
T temp = first; first = second; second = temp;
}
Chapter 18 Introducing Generics |
351 |
You invoke the method by specifying the appropriate type for its type parameter. The following examples show how to invoke the Swap<T> method to swap over two ints and two strings:
int a = 1, b = 2; Swap<int>(ref a, ref b);
...
string s1 = “Hello”, s2 = “World”; Swap<string>(ref s1, ref s2);
Note Just as instantiating a generic class with different type parameters causes the compiler to generate different types, each distinct use of the Swap<T> method causes the compiler to generate a different version of the method. Swap<int> is not the same method as Swap<string>; both
methods just happen to have been generated from the same generic method, so they exhibit the same behavior, albeit over different types.
Defining a Generic Method to Build a Binary Tree
The preceding exercise showed you how to create a generic class for implementing a binary tree. The Tree<TItem> class provides the Insert method for adding data items to the tree. However, if you want to add a large number of items, repeated calls to the Insert method
are not very convenient. In the following exercise, you will define a generic method called InsertIntoTree that you can use to insert a list of data items into a tree with a single method
call. You will test this method by using it to insert a list of characters into a tree of characters.
Write the InsertIntoTree method
1.Using Visual Studio 2008, create a new project by using the Console Application template. In the New Project dialog box, name the project BuildTree. If you are us-
ing Visual Studio 2008 Standard Edition or Visual Studio 2008 Professional Edition, set the Location to \Microsoft Press\Visual CSharp Step By Step\Chapter 18 under your Documents folder, and select Create a new Solution from the Solution drop-down list. Click OK.
2.On the Project menu, click Add Reference. In the Add Reference dialog box, click the
Browse tab. Move to the folder \Microsoft Press\Visual CSharp Step By Step\Chapter 18 \BinaryTree\BinaryTree\bin\Debug, click BinaryTree.dll, and then click OK.
The BinaryTree assembly is added to the list of references shown in Solution Explorer.
3.In the Code and Text Editor window displaying the Program.cs file, add the following using directive to the top of the Program.cs file:
using BinaryTree;
This namespace contains the Tree<TItem> class.
352Part III Creating Components
4.Add a method called InsertIntoTree to the Program class after the Main method. This should be a static method that takes a Tree<TItem> variable and a params array of TItem elements called data.
The method definition should look like this:
static void InsertIntoTree<TItem>(Tree<TItem> tree, params TItem[] data)
{
}
Tip An alternative way of implementing this method is to create an extension method of the Tree<TItem> class by prefixing the Tree<TItem> parameter with the this keyword and defining the InsertIntoTree method in a static class, like this:
public static class TreeMethods
{
public static void InsertIntoTree<TItem>(this Tree<TItem> tree, params TItem[] data)
{
...
}
...
}
The principal advantage of this approach is that you can invoke the InsertIntoTree method directly on a Tree<TItem> object rather than pass the Tree<TItem> in as a parameter.
However, for this exercise, we will keep things simple.
5.The TItem type used for the elements being inserted into the binary tree must implement the IComparable<TItem> interface. Modify the definition of the InsertIntoTree method and add the appropriate where clause, as shown in bold type in the following code.
static void InsertIntoTree<TItem>(Tree<TItem> tree, params TItem[] data) where TItem :
IComparable<TItem>
{
}
6.Add the following statements shown in bold type to the InsertIntoTree method. These
statements check to make sure that the user has actually passed some parameters into the method (the data array might be empty), and then they iterate through the params list, adding each item to the tree by using the Insert method. The tree is passed back as the return value:
static void InsertIntoTree<TItem>(Tree<TItem> tree, params TItem[] data) where TItem : IComparable<TItem>
{
if (data.Length == 0)
throw new ArgumentException(“Must provide at least one data value”);
Chapter 18 Introducing Generics |
353 |
foreach (TItem datum in data)
{
tree.Insert(datum);
}
}
Test the InsertIntoTree method
1.In the Main method of the Program class, add the following statements shown in bold type that create a new Tree for holding character data, populate it with some sample data by using the InsertIntoTree method, and then display it by using the WalkTree method of Tree:
static void Main(string[] args)
{
Tree<char> charTree = new Tree<char>(‘M’); InsertIntoTree<char>(charTree, ‘X’, ‘A’, ‘M’, ‘Z’, ‘Z’, ‘N’); charTree.WalkTree();
}
2.On the Build menu, click Build Solution. Verify that the solution compiles, and correct any errors if necessary.
3.On the Debug menu, click Start Without Debugging.
The program runs and displays the character values in the following order: A, M, M, N, X, Z, Z
4.Press the Enter key to return to Visual Studio 2008.
If you want to continue to the next chapter
Keep Visual Studio 2008 running and turn to Chapter 19. If you want to exit Visual Studio 2008 now
On the File menu, click Exit. If you see a Save dialog box, click Yes (if you are using Visual Studio 2008) or Save (if you are using Visual C# 2008 Express Edition) and save the project.
