Tải bản đầy đủ (.pdf) (884 trang)

programming in c# with visual studio 2010 vol II (microsoft)

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (20.69 MB, 884 trang )

OFFICIAL MICROSOFT LEARNING PRODUCT
10266A
Programming in C# with
Microsoft® Visual Studio® 2010
Be sure to access the extended learning content on your Course
Companion CD enclosed on the back cover of the book.


ii Programming in C# with Microsoft® Visual Studio® 2010
Information in this document, including URL and other Internet Web site references, is subject to
change without notice. Unless otherwise noted, the example companies, organizations, products,
domain names, e-mail addresses, logos, people, places, and events depicted herein are fictitious,
and no association with any real company, organization, product, domain name, e-mail address,
logo, person, place or event is intended or should be inferred. Complying with all applicable
copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part
of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted
in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for
any purpose, without the express written permission of Microsoft Corporation.
Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual
property rights covering subject matter in this document. Except as expressly provided in any
written license agreement from Microsoft, the furnishing of this document does not give you any
license to these patents, trademarks, copyrights, or other intellectual property.
The names of manufacturers, products, or URLs are provided for informational purposes only and
Microsoft makes no representations and warranties, either expressed, implied, or statutory,
regarding these manufacturers or the use of the products with any Microsoft technologies. The
inclusion of a manufacturer or product does not imply endorsement of Microsoft of the
manufacturer or product. Links may be provided to third party sites. Such sites are not under the
control of Microsoft and Microsoft is not responsible for the contents of any linked site or any link
contained in a linked site, or any changes or updates to such sites. Microsoft is not responsible for
webcasting or any other form of transmission received from any linked site. Microsoft is providing
these links to you only as a convenience, and the inclusion of any link does not imply endorsement


of Microsoft of the site or the products contained therein.
© 2010 Microsoft Corporation. All rights reserved.
Microsoft, and Windows are either registered trademarks or trademarks of Microsoft Corporation in
the United States and/or other countries.
All other trademarks are property of their respective owners.





Product Number: 10266A
Part Number: 01918
Released: 09/2010


Programming in C# with Microsoft® Visual Studio® 2010 v
Contents
Module 1: Introducing C# and the .NET Framework
Lesson 1: Introduction to the .NET Framework 4 1-4
Lesson 2: Creating Projects Within Visual Studio 2010 1-16
Lesson 3: Writing a C# Application 1-33
Lesson 4: Building a Graphical Application 1-44
Lesson 5: Documenting an Application 1-58
Lesson 6: Debugging Applications by Using Visual Studio 2010 1-66
Lab: Introducing C# and the .NET Framework 1-78
Module 2: Using C# Programming Constructs
Lesson 1: Declaring Variables and Assigning Values 2-4
Lesson 2: Using Expressions and Operators 2-23
Lesson 3: Creating and Using Arrays 2-36
Lesson 4: Using Decision Statements 2-49

Lesson 5: Using Iteration Statements 2-63
Lab: Using C# Programming Constructs 2-78
Module 3: Declaring and Calling Methods
Lesson 1: Defining and Invoking Methods 3-3
Lesson 2: Specifying Optional Parameters and Output Parameters 3-29
Lab: Declaring and Calling Methods 3-39
Module 4: Handling Exceptions
Lesson 1: Handling Exceptions 4-3
Lesson 2: Raising Exceptions 4-23
Lab: Handling Exceptions 4-34


vi Programming in C# with Microsoft® Visual Studio® 2010
Module 5: Reading and Writing Files
Lesson 1: Accessing the File System 5-3
Lesson 2: Reading and Writing Files by Using Streams 5-27
Lab: Reading and Writing Files 5-45
Module 6: Creating New Types
Lesson 1: Creating and Using Enumerations 6-3
Lesson 2: Creating and Using Classes 6-12
Lesson 3: Creating and Using Structures 6-33
Lesson 4: Comparing References to Values 6-41
Lab: Creating New Types 6-55
Module 7: Encapsulating Data and Methods
Lesson 1: Controlling Visibility of Type Members 7-4
Lesson 2: Sharing Methods and Data 7-15
Lab: Encapsulating Data and Methods 7-29
Module 8: Inheriting from Classes and Implementing Interfaces
Lesson 1: Using Inheritance to Define New Reference Types 8-3
Lesson 2: Defining and Implementing Interfaces 8-27

Lesson 3: Defining Abstract Classes 8-45
Lab: Inheriting from Classes and Implementing Interfaces 8-56
Module 9: Managing the Lifetime of Objects and Controlling Resources
Lesson 1: Introduction to Garbage Collection 9-4
Lesson 2: Managing Resources 9-21
Lab: Managing the Lifetime of Objects and Controlling Resources 9-35
Module 10: Encapsulating Data and Defining Overloaded Operators
Lesson 1: Creating and Using Properties 10-4
Lab A: Creating and Using Properties 10-26
Lesson 2: Creating and Using Indexers 10-38
Lab B: Creating and Using Indexers 10-50
Programming in C# with Microsoft® Visual Studio® 2010 vii
Lesson 3: Overloading Operators 10-60
Lab C: Overloading Operators 10-79
Module 11: Decoupling Methods and Handling Events
Lesson 1: Declaring and Using Delegates 11-4
Lesson 2: Using Lambda Expressions 11-14
Lesson 3: Handling Events 11-22
Lab: Decoupling Methods and Handling Events 11-38
Module 12: Using Collections and Building Generic Types
Lesson 1: Using Collections 12-4
Lab A: Using Collections 12-22
Lesson 2: Creating and Using Generic Types 12-28
Lesson 3: Defining Generic Interfaces and Understanding Variance 12-42
Lesson 4: Using Generic Methods and Delegates 12-56
Lab B: Building Generic Types 12-69
Module 13: Building and Enumerating Custom Collection Classes
Lesson 1: Implementing a Custom Collection Class 13-3
Lesson 2: Adding an Enumerator to a Custom Collection Class 13-21
Lab: Building and Enumerating Custom Collection Classes 13-37

Module 14: Using LINQ to Query Data
Lesson 1: Using the LINQ Extension Methods and Query Operators 14-3
Lesson 2: Building Dynamic LINQ Queries and Expressions 14-28
Lab: Using LINQ to Query Data 14-47
Module 15: Integrating Visual C# Code with Dynamic Languages and COM
Components
Lesson 1: Integrating Visual C# Code with Ruby and Python 15-4
Lesson 2: Accessing COM Components from Visual C# 15-19
Lab: Integrating Visual C# Code with Dynamic Languages and COM
Components 15-36
viii Programming in C# with Microsoft® Visual Studio® 2010
Appendix: Lab Answer Keys
Module 1 Lab: Introducing C# and the .NET Framework L1-1
Module 2 Lab: Using C# Programming Constructs L2-1
Module 3 Lab: Declaring and Calling Methods L3-1
Module 4 Lab: Handling Exceptions L4-1
Module 5 Lab: Reading and Writing Files L5-1
Module 6 Lab: Creating New Types L6-1
Module 7 Lab: Encapsulating Data and Methods L7-1
Module 8 Lab: Inheriting from Classes and Implementing Interfaces L8-1
Module 9 Lab: Managing the Lifetime of Objects and Controlling
Resources L9-1
Module 10 Lab A: Creating and Using Properties L10A-1
Module 10 Lab B: Creating and Using Indexers L10B-1
Module 10 Lab C: Overloading Operators L10C-1
Module 11 Lab: Decoupling Methods and Handling Events L11-1
Module 12 Lab A: Using Collections L12A-1
Module 12 Lab B: Building Generic Types L12B-1
Module 13 Lab: Building and Enumerating Custom Collection Classes L13-1
Module 14 Lab: Using LINQ to Query Data L14-1

Module 15 Lab: Integrating Visual C# Code with Dynamic Languages
and COM Components L15-1



Encapsulating Data and Defining Overloaded Operators 10-1
Module 10
Encapsulating Data and Defining Overloaded
Operators
Contents:
Lesson 1: Creating and Using Properties 10-4
Lab A: Creating and Using Properties 10-26
Lesson 2: Creating and Using Indexers 10-38
Lab B: Creating and Using Indexers 10-50
Lesson 3: Overloading Operators 10-60
Lab C: Overloading Operators 10-79

10-2 Programming in C# with Microsoft® Visual Studio® 2010
Module Overview

Nearly every application you develop will require you to develop at least one type
to represent some entity. Types typically expose methods and data. A simple
approach to exposing data is to make the fields used by your class public; however,
this is often bad practice—or at least is not the most secure, efficient, or natural
technique.
For example, providing an array-like syntax may be a better approach when
accessing data in a class that stores a collection of data. Similarly, if a class exposes
a member that should have only read-only access, exposing a field publicly
provides both read and write access. This module will introduce you to properties
and indexers. These are elements of Microsoft® Visual C#® that enable you to

encapsulate data and expose data appropriately and efficiently.
Another syntax you will commonly use is that associated with operators. For
example, it is intuitive to write 2 + 3 and expect that the result will be 5. Similarly,
you will probably expect "Hello"+ "World" to return the concatenated string
"HelloWorld". Many operators have well-defined behavior for the built-in Visual C#
types, but you can also define operators for your own types. This module describes
how to implement operators for your types by using overloading.
Encapsulating Data and Defining Overloaded Operators 10-3
Objectives
After completing this module, you will be able to:
• Explain how properties work and use them to encapsulate data.
• Describe how to use indexers to provide access to data through an array-like
syntax.
• Describe how to use operator overloading to define operators for your own
types.

10-4 Programming in C# with Microsoft® Visual Studio® 2010
Lesson 1
Creating and Using Properties

You can use properties to provide controlled access to the data in a type. This
lesson introduces you to properties and shows you how to define them in your
types. It also explains why you should use this approach to encapsulate data.
Objectives
After completing this lesson, you will be able to:
• Describe the purpose of properties.
• Implement properties.
• Explain automatic properties.
• Instantiate an object by using properties.
• Define properties in an interface.

• Describe the best practices relating to properties.
Encapsulating Data and Defining Overloaded Operators 10-5
What Is a Property?

Key Points
A property is a cross between a field and a method. You use field-like syntax to
access a property. However, the behavior of a property is more like a method.
A property can contain two elements:
• A get accessor, which an application can use to read the property value.
• A set accessor, which an application can use to change the property value.

Properties are a common way of encapsulating data exposed by your class.
Normally a property is mapped to a private field in your type. The field stores the
data, and the get and set accessors of the property provide a mechanism for
accessing that field. You are not obliged to provide both a get and a set accessor, so
properties have the advantage that you can control whether to make a property
read-only, write-only, or make the property readable and writeable which you
cannot do by exposing a field.
Another advantage of using a property is the ability to validate data. If you expose a
field in your type, any other type can read or write to that field. As long as the data
10-6 Programming in C# with Microsoft® Visual Studio® 2010
is of the right type, any value can be assigned to that field. This is not always
logical; sometimes you may need to restrict the range of acceptable values for a
field in your type. With a property, you can add logic to the set accessor to check
that a value falls in the expected range before updating the private field.
Although properties normally map to private fields, there is no requirement for
them to do so. The get accessor of a property can return a calculated value, a
constant value, or perform any other operation applicable to your application.
Properties will often include additional logic; for example, if you update a file name
by using a property, the property may check whether the file is currently in use

and, if necessary, rename the file or open a new file according to the requirements
of the application.
Question: How does the behavior of a method differ from a property?
Additional Reading
For more information about properties, see the Properties (C# Programming
Guide) page at

Encapsulating Data and Defining Overloaded Operators 10-7
Defining a Property

Key Points
A property has a type and a name, in much the same way as a field. However, the
logic for a property is defined by the get and set accessors.
The get accessor, like a method, can include any code; however, it must return an
object of the type specified by the property or throw an exception. The set accessor
does not have to perform any function—although normally, you update a private
field to perform some operation based on the value passed to the property. You do
not specify a parameter for the set accessor; a set accessor always takes one
parameter of the type exposed by the property. You can access the object passed as
a parameter to a set accessor by using the value keyword.
The following code example shows how to define a simple property that provides
access to a private field. The get keyword introduces a code block that defines the
code that runs when an application reads the property. The set keyword defines
the code block for the logic that runs when an application assigns a value to the
property.

10-8 Programming in C# with Microsoft® Visual Studio® 2010
private string myString;

public string MyString

{
get
{
return this.myString;
}
set
{
this.myString = value;
}
}
To define a read-only property, you simply omit the set accessor. Similarly, to
define a write-only property, do not implement a get accessor.
Defining Property Accessibility
When you define a property, you specify the access modifier for that property. The
access modifier that you specify for a property is inherited by the get and set
accessors. You can override the access modifier for either the get or set accessor;
however, you cannot make an accessor more accessible than the containing
property. For example, you cannot make the get accessor public if the property is
private.
The following code example shows how to modify the accessibility level at the
accessor level.
public string MyString
{
get
{
return this.myString;
}
private set
{
myString = value;

}
}
Using a Property in a Consuming Class
You use a property in a consuming class by using the dot notation in the same way
as you access a public field. The following code example shows how to access the
MyString property from the previous code example. Internally, the Visual C#
Encapsulating Data and Defining Overloaded Operators 10-9
compiler converts all attempts to read the property into calls to the get accessor
and changes all attempts to write the property into calls to the set accessor.
MyObject theClass = new MyObject;

// Setting the string – calls the set accessor
theClass.MyString = "Property set.";

// Getting the string – calls the get accessor
Console.WriteLine(theClass.MyString);

Note: You can define static properties, but they can only access static data.
Question: How can you enable write access to a property to other types in the
same assembly, but read access to a property from a class in any assembly?
Additional Reading
For more information about using properties, see the Using Properties (C#
Programming Guide) page at

10-10 Programming in C# with Microsoft® Visual Studio® 2010
Automatic Properties

Key Points

When you develop a new type, you may include a data field that you want to

expose to applications. If no additional processing or validation is required on that
field, it may be tempting to simply expose the field publicly instead of adding a
property to provide access to that field.
In this case, exposing a field may not seem like a problem. However, remember
that you cannot add code to prevent invalid values in a field but you can in a
property. Whether you need to add validation or other logic to a property when
you originally develop a type does not mean that will always be the case. The
requirements of your type may change over the lifetime of the application.
From a developer's perspective, using a property is exactly the same as using a
field; however, this is not true to the compiler. The compiler converts code that
accesses a property into a method call to the get accessor, and it similarly converts
writing to a property to a method call to the set accessor. This has implications for
existing applications if you must convert a field to a property at a later date; any
application that used the type with the value exposed as a field must be recompiled
Encapsulating Data and Defining Overloaded Operators 10-11
with the data exposed through a property. If this type is in an assembly used by a
number of applications, you may need to rebuild and redeploy a lot of
installations.
You can avoid this extra work by simply exposing the data through a property
when you originally develop the type. Any future changes to the type can then be
made without the need to recompile applications that consume your type.
Where you must expose a field, and are tempted to simply make the field public
rather than writing a property to get and set the field, you can use automatic
properties.
Automatic properties provide a simple inline syntax that converts a field to a
property. To use automatic properties, you simply add curly braces that contain
both set and get accessors, each followed by a semicolon, as the following code
example shows.
public string Name { get; set; }
When you use an automatic property, the compiler creates a private field and

automatically generates code to read and write this field, as the following code
example shows.
private string _name;

public string Name
{
get
{
return this._name;
}
set
{
this._name = value;
}
}

Note: Automatic properties always define both a get and set accessor. Automatic
properties are intended for use where otherwise you would simply expose a public field.
If you require more specific control over the data, you must write the property manually.
It does not make any difference to consuming classes if you change from an automatic
property to a manual property in a later build of your code; they are completely
interchangeable, unlike properties and fields.
10-12 Programming in C# with Microsoft® Visual Studio® 2010
Question: What is the benefit of using an automatic property compared to
exposing a public field?
Encapsulating Data and Defining Overloaded Operators 10-13
Instantiating an Object by Using Properties

Key Points
You have previously seen how to use a constructor to instantiate an object and

initialize its fields. You can declare several constructors, with different signatures,
to enable other developers to set various combinations of fields in your type to
appropriate values; however, this approach is problematic if you have more than a
small number of fields or several properties of the same type.
The following code example shows a simple class with several constructors.
class Employee
{
private string name;
private string department;

// Initialize both fields
public Employee(string empName, string empDepartment)
{
this.name = Name;
this.department = Department;
}

10-14 Programming in C# with Microsoft® Visual Studio® 2010
// Initialize name only
public Employee(string empName)
{
this.name = empName;
}

// Initialize department only
public Employee(string empDepartment)
{
this.department = empDepartment
}


}
The intention of the constructors is to enable an application to specify a value for
the employee name, department name, or both when it creates a new Employee
object. However, this code will not compile because the compiler cannot
distinguish between the two constructors that take a single string parameter. If you
attempt to instantiate an Employee object by using the code shown in the
following code example, the compiler does not know which constructor to use.
// Is "Fred" the name of an employee or a department?
Employee myEmployee = new Employee("Fred");
You can resolve this problem by using properties to initialize the object when you
instantiate it. This syntax is known as an object initalizer. With an object initializer,
you create a new object by using a constructor, but you specify the values to assign
to properties after the constructor has completed by using property name/value
assignment pairs separated by commas and enclosed in curly braces.
The following code example shows how to define a class that supports object
initializers and how to create an object by using them.
class Employee
{
// Default constructor.
public Employee()
{

}

// Constructor that sets the grade of an employee.
public Employee(int grade)
{

}


Encapsulating Data and Defining Overloaded Operators 10-15
// Expose Name and Department as automatic properties.
public string Name { get; set; }
public string Department { get; set; }

}

// Instantiating an object and setting a single property.
Employee louisa = new Employee() { Department = "Technical" };

// Instantiating an object and setting a single property.
// You do not have to add the brackets to use the default constructor.
Employee john = new Employee { Name = "John" };


// Instantiating an object and setting a multiple properties.
// Separate properties with a comma.
Employee mike = new Employee
{
Name = "Mike",
Department = "Technical"
};
In the first example, (louisa), the default constructor is used to create the
Employee object. After the object is created and the constructor has finished, the
value "Technical" is assigned to the Department property. Note that if you use the
default constructor, you can omit the brackets (), as the second example (john)
and the third example (mike) illustrate.
If the Employee class has a nondefault constructor, you can invoke that together
with an object initializer, as the following code example shows. This code example
uses the constructor that sets the grade of an employee.

Employee antony =
new Employee(2) { Name = "Antony", Department = "Management" };
When you use an object initializer, the constructor logic runs first, and then the
properties are set to the values specified in the object initializer. This means that if
you set a property in a constructor, and then set the same property in the object
initializer, the value from the object initializer will overwrite the value set by the
constructor.

Hint: You should only define constructors that set any required properties to default
values. Classes that consume your type can then override those properties in an object
initializer.
10-16 Programming in C# with Microsoft® Visual Studio® 2010
Question: Why is it important to instantiate required properties to default values
in the constructor?
Encapsulating Data and Defining Overloaded Operators 10-17
Defining Properties in an Interface

Key Points
An interface defines a contract that specifies the methods that a class should
implement. An interface can also define properties. However, the implementation
details of these properties (such as the fields they reference, if any) are the
responsibility of the class.
To add a property to an interface, you use the same syntax as an automatic
property, except you cannot specify an access modifier. The following code
example shows properties added to an interface.
interface IPerson
{
string Name { get; set; }
int Age { get; }
DateTime DateOfBirth { set; }

}
Classes that implement an interface that includes properties can implement the
properties implicitly or explicitly.
10-18 Programming in C# with Microsoft® Visual Studio® 2010
The following code example shows the IPerson interface implemented implicitly.
class Person : IPerson
{
public string Name
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}

public int Age
{
get { throw new NotImplementedException(); }
}

public DateTime DateOfBirth
{
set { throw new NotImplementedException(); }
}
}
The following code example shows the IPerson interface implemented explicitly.

class Person : IPerson
{
string IPerson.Name
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}

int IPerson.Age
{
get { throw new NotImplementedException(); }
}

DateTime IPerson.DateOfBirth
Encapsulating Data and Defining Overloaded Operators 10-19
{
set { throw new NotImplementedException(); }
}
}
Question: When should you add a property to an interface?
Additional Reading
For more information about defining properties in an interface, see the Interface
Properties (C# Programming Guide) page at



×