- •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
200 |
Part II Understanding the C# Language |
|
The output from this program is sorted alphabetically by the names of my family members: |
|
Name: Diana, Age: 43 |
|
Name: Francesca, Age: 13 |
|
Name: James, Age: 15 |
|
Name: John, Age: 42 |
Using Collection Initializers
The examples in the preceding subsections have shown you how to add individual elements to a collection by using the method most appropriate to that collection (Add for an ArrayList, Enqueue for a Queue, Push for a Stack, and so on). You can also initialize some collection
types when you declare them, using a syntax very similar to that supported by arrays. For example, the following statement creates and initializes the numbers ArrayList object shown
earlier, demonstrating an alternative technique to repeatedly calling the Add method:
ArrayList numbers = new ArrayList(){10, 9, 8, 7, 7, 6, 5, 10, 4, 3, 2, 1};
Internally, the C# compiler actually converts this initialization to a series of calls to the Add
method. Consequently, you can use this syntax only for collections that actually support the Add method. (The Stack and Queue classes do not.)
For more complex collections such as Hashtable that take key/value pairs, you can specify each key/value pair as an anonymous type in the initializer list, like this:
Hashtable ages = new Hashtable(){{“John”, 42}, {“Diana”, 43}, {“James”, 15}, {“Francesca”, 13}};
The first item in each pair is the key, and the second is the value.
Comparing Arrays and Collections
Here’s a summary of the important differences between arrays and collections:
An array declares the type of the elements that it holds, whereas a collection doesn’t. This is because the collections store their elements as objects.
An array instance has a fixed size and cannot grow or shrink. A collection can dynamically resize itself as required.
An array can have more than one dimension. A collection is linear.
Note The items in a collection can be other collections, enabling you to mimic a multidimensional array, although a collection containing other collections can be somewhat confusing to use.
Chapter 10 Using Arrays and Collections |
201 |
Using Collection Classes to Play Cards
The next exercise presents a Microsoft Windows Presentation Foundation (WPF) application that simulates dealing a pack of cards to four players. Cards will either be in the pack or
be in one of four hands dealt to the players. The pack and hands of cards are implemented as ArrayList objects. You might think that these should be implemented as an array—after
all, there are always 52 cards in a pack and 13 cards in a hand. This is true, but it overlooks the fact that when you deal the cards to players’ hands, the cards are no longer in the pack.
If you use an array to implement a pack, you’ll have to record how many slots in the array actually hold a PlayingCard and how many have been dealt to players. Similarly, when you
return cards from a player’s hand to the pack, you’ll have to record which slots in the hand no longer contain a PlayingCard.
You will study the code and then write two methods: one to shuffle a pack of cards and one to return the cards in a hand to the pack.
Deal the cards
1.Start Microsoft Visual Studio 2008 if it is not already running.
2.Open the Cards project, located in the \Microsoft Press\Visual CSharp Step by Step\ Chapter 10\Cards folder in your Documents folder.
3.On the Debug menu, click Start Without Debugging.
Visual Studio 2008 builds and runs the program. The form displays the cards in the hands of the four players (North, South, West, and East). There are also two buttons: one to deal the cards and one to return the cards to the pack.
4.On the form, click Deal.
The 52 cards in the pack are dealt to the four hands, 13 cards per hand, as shown here:
As you can see, the cards have not yet been shuffled. You will implement the Shuffle method in the next exercise.
202Part II Understanding the C# Language
5.Click Return to Pack.
Nothing happens because the method to return the cards to the pack has also not yet been written.
6.Click Deal again.
This time the cards in each of the hands disappear, because before the cards are dealt, each hand is reset. Because there are no cards left in the pack (the method to return cards to the pack has not been written yet either), there is nothing to deal.
7.Close the form to return to the Visual Studio 2008 programming environment.
Now that you know which parts are missing from this application, you will add them.
Shuffle the pack
1.Display the Pack.cs file in the Code and Text Editor window.
2.Scroll through the code, and examine it.
The Pack class represents a pack of cards. It contains a private ArrayList field named cards. Notice also that the Pack class has a constructor that creates and adds the 52 playing cards to the ArrayList by using the Accept method defined by this class. The
methods in this class constitute the typical operations that you would perform on a pack of cards (Shuffle, Deal).
3.Display the PlayingCard.cs file in the Code and Text Editor window, and examine its contents.
Playing cards are represented by the PlayingCard class. A playing card exposes two fields of note: suit (which is an enumerated type and is one of Clubs, Diamonds, Hearts, or Spades) and pips (which indicates the numeric value of the card).
4.Return to the Pack.cs file and locate the Shuffle method in the Pack class.
The method is not currently implemented. There are a number of ways you can simulate shuffling a pack of cards. Perhaps the simplest technique is to choose each card in
sequence and swap it with another card selected at random. The .NET Framework contains a class named Random that you can use to generate random integer numbers.
5.Declare a local variable of type Random named random, and initialize it to a newly created Random object by using the default Random constructor, as shown here in bold. The Shuffle method should look like this:
public void Shuffle()
{
Random random = new Random();
}
6.Add a for statement with an empty body that iterates an int i from 0 up to the number of elements inside the cards ArrayList, as shown here in bold:
Chapter 10 Using Arrays and Collections |
203 |
public void Shuffle()
{
Random random = new Random();
for (int i = 0; i < cards.Count; i++)
{
}
}
The next step is to choose a random index between 0 and cards.Count – 1. You will then
swap the card at index i with the card at this random index. You can generate a positive random integer by calling the Random.Next instance method. You can specify an upper limit for the random number generated by Random.Next as a parameter.
Notice that you have to use a for statement here. A foreach statement would not work because you need to modify each element in the ArrayList and a foreach loop limits
you to read-only access.
7.Inside the for statement, declare a local variable named cardToSwap, and initialize it to a random number between 0 and cards.Count – 1 (inclusive), as shown here in bold:
public void Shuffle()
{
Random random = new Random();
for (int i = 0; i < cards.Count; i++)
{
int cardToSwap = random.Next(cards.Count - 1);
}
}
The final step is to swap the card at index i with the card at index cardToSwap. To do this, you must use a temporary local variable.
8.Add three statements to swap the card at index i with the card at index cardToSwap. Remember that the elements inside a collection class (such as ArrayList) are of type object. Also, notice that you can use regular array notation (square brackets and an index) to access existing elements in an ArrayList.
The Shuffle method should now look exactly like this (the new statements are shown in bold):
public void Shuffle()
{
Random random = new Random();
for (int i = 0; i < cards.Count; i++)
{
int cardToSwap = random.Next(cards.Count - 1); object temp = cards[i];
cards[i] = cards[cardToSwap]; cards[cardToSwap] = temp;
}
}
204Part II Understanding the C# Language
9.On the Debug menu, click Start Without Debugging.
10.On the form, click Deal.
This time the pack is shuffled before dealing, as shown here. (Your screen will differ slightly each time, because the card order is now random.)
11. Close the form.
The final step is to add the code to return the cards to the pack so that they can be dealt again.
Return the cards to the pack
1.Display the Hand.cs file in the Code and Text Editor window.
The Hand class, which also contains an ArrayList named cards, represents the cards held by a player. The idea is that at any one time, each card is either in the pack or in a hand.
2.Locate the ReturnCardsTo method in the Hand class.
The Pack class has a method named Accept that takes a single parameter of type PlayingCard. You need to create a loop that goes through the cards in the hand and passes them back to the pack.
3.Complete the ReturnCardsTo method as shown here in bold:
public void ReturnCardsTo(Pack pack)
{
foreach (PlayingCard card in cards)
{
pack.Accept(card);
}
cards.Clear();
}
Chapter 10 Using Arrays and Collections |
205 |
A foreach statement is convenient here because you do not need write access to the element and you do not need to know the index of the element. The Clear method removes all elements from a collection. It is important to call cards.Clear after returning the cards to the pack so that the cards aren’t in both the pack and the hand. The Clear method of the ArrayList class empties the ArrayList of its contents.
4.On the Debug menu, click Start Without Debugging.
5.On the form, click Deal.
The shuffled cards are dealt to the four hands as before.
6.Click Return to Pack.
The hands are cleared. The cards are now back in the pack.
7.Click Deal again.
The shuffled cards are once again dealt to the four hands.
8.Close the form.
Note If you click the Deal button twice without clicking Return to Pack, you lose all the cards. In the real world, you would disable the Deal button until the Return to Pack button
was clicked. In Part IV, “Working with Windows Applications,” we will look at using C# to write code that modifies the user interface.
In this chapter, you have learned how to create and use arrays to manipulate sets of data. You have also seen how to use some of the common collection classes to store and access data in memory in different ways.
If you want to continue to the next chapter:
Keep Visual Studio 2008 running, and turn to Chapter 11.
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.