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

Tài liệu Module 6: Working with Types pptx

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 (828.41 KB, 48 trang )








Contents
Overview 1
System.Object Class Functionality 2
Specialized Constructors 12
Type Operations 18
Interfaces 28
Managing External Types 34
Lab 6: Working with Types 38
Review 43

Module 6:
Working with Types



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.

 2001-2002 Microsoft Corporation. All rights reserved.

Microsoft, ActiveX, BizTalk, IntelliMirror, Jscript, MSDN, MS-DOS, MSN, PowerPoint,
Visual Basic, Visual C++, Visual C#, Visual Studio, Win32, Windows, Windows Media, and
Window NT are either registered trademarks or trademarks of Microsoft Corporation in the U.S.A.
and/or other countries.

The names of actual companies and products mentioned herein may be the trademarks of their
respective owners.



Module 6: Working with Types iii


Instructor Notes
After completing this module, students will be able to:
!
Apply attributes to control visibility and inheritance in classes and
interfaces.
!
Create and use interfaces that define methods and properties.
!
Explain how boxing and unboxing works and when it occurs.

!
Use operators to determine types at run time and cast values to different
types.
!
Explain what features are available to work with unmanaged types, such as
COM types.

Materials and Preparation
This section provides the materials and preparation tasks that you need to teach
this module.
Required Materials
To teach this module, you need the Microsoft
®
PowerPoint
®
file 2349B_06.ppt.
Preparation Tasks
To prepare for this module, you should:
!
Read all of the materials for this module.
!
Complete the lab.

Presentation:
75 Minutes

Lab:
45 Minutes
iv Module 6: Working with Types



Module Strategy
Use the following strategy to present this module:
!
System.Object Class Functionality
In this section, discuss how System.Object provides classes to generate
hash functions, represent strings, and compare objects for identity and
equality.
Explain that this section does not cover all of the classes in System.Object,
and that other classes are covered elsewhere in the course. For example,
finalization and the Finalize method are covered in detail in Module 9,
“Memory and Resource Management,” in Course 2349B, Programming
with the Microsoft .NET Framework (Microsoft Visual C#

.NET).
!
Specialized Constructors
This section covers more advanced types of constructors. Explain how static
constructors work, when to use them, and when to use private constructors.
If the students in your class already have experience in C++, you may not
need to spend much time on these topics.
!
Type Operations
The Microsoft .NET Framework common language runtime supports a
variety of type operations for working with types. Discuss conversions and
conversion operators for determining and converting the type of an object.
Also cover how to cast types for conversion and for treating a type as a
different type.
For experienced C++ programmers, you may be able to cover type
conversion and casting quickly. C++ programmers may find it useful that

the as operator in C# is similar to dynamic_cast in C++.
Spend most of this section discussing boxing and unboxing. Students will
need to be aware of the performance consequences of boxing. Explain how
you can avoid or minimize these consequences if you must use boxing.
!
Interfaces
Discuss how multiple inheritance works through interfaces and explain how
to explicitly implement interfaces.
As with the other topics in this module, you may be able to cover this
section quickly if your audience is already familiar with object-oriented
programming techniques.
For experienced C++ programmers, consider mentioning that explicit
interface implementation was not possible in C++.
!
Managing External Types
Briefly introduce Platform Invocation Services and COM interoperability.
Be aware that more information about these topics is available in Module
15, “Interoperating Between Managed and Unmanaged Code,” in Course
2349B, Programming with the Microsoft .NET Framework (Microsoft
Visual C# .NET) and “Interoperating with Unmanaged Code” in the .NET
Framework SDK documentation.

Module 6: Working with Types 1


Overview
!
System.Object Class Functionality
!
Specialized Constructors

!
Type Operations
!
Interfaces
!
Managing External Types

*****************************
ILLEGAL FOR NON
-
TRAINER USE
******************************
In this module, you will learn how to apply your knowledge of the Common
Type System to various programming scenarios. This module will help you
understand how to use types efficiently when developing Microsoft
®
.NET
Framework applications. You should understand that many nuances in the type
system can affect program clarity and performance if ignored.
This module covers the use of attributes to control visibility and inheritance on
types and explains how to work with various type operations, such as boxing
and unboxing, and type operators. The module then explores how to work with
types programmatically by using operators to coerce, cast, or discover types at
run time.
In addition, this module discusses how to build an interface that supports
methods and properties and how to make interface designs more efficient.
The module also highlights features that are designed to help you work with
unmanaged types, such as COM types.
After completing this module, you will be able to:
!

Apply attributes to control visibility and inheritance in classes and
interfaces.
!
Create and use interfaces that define methods and properties.
!
Explain how boxing and unboxing works and when it occurs.
!
Use operators to determine types at run time and cast values to different
types.
!
Explain what features are available to work with unmanaged types, such as
COM types.

Topic Objective
To provide an overview of
the module topics and
objectives.
Lead-in
In this module, you will learn
how to apply your
knowledge of the Common
Type System to various
programming scenarios.
2 Module 6: Working with Types


"
""
"


System.Object Class Functionality
!
Hash Codes
!
Identity
!
Equality
!
String Representation

*****************************
ILLEGAL FOR NON
-
TRAINER USE
******************************
In this section, you will learn about the common methods that you need to
override on the System.Object class.
This section does not cover finalization and the Finalize method, which are
covered in detail in Module 9, “Memory and Resource Management,” in
Course 2349B, Programming with the Microsoft .NET Framework (Microsoft
Visual C#

.NET). Also, this section does not cover the MemberwiseClone
method.
Topic Objective
To provide an overview of
the topics covered in this
section.
Lead-in
In this section, you will learn

about the common methods
that you need to override on
the System.Object class.
Module 6: Working with Types 3


Hash Codes
!
Hash Code Used to Perform Quick Lookups
!
Override GetHashCode Method on System.Object
!
Should Return Same Hash Code for Objects of
Same Value
!
Should Implement Efficient Algorithm
struct Student {
string name;
int ID; //Unique for each instance
public override int GetHashCode() {
return ID;
}
}
struct Student {
string name;
int ID; //Unique for each instance
public override int GetHashCode() {
return ID;
}
}


*****************************
ILLEGAL FOR NON
-
TRAINER USE
******************************
A hash function is used to quickly generate a number, or hash code, that
corresponds to the value of an object. Hash codes are useful for performing
quick lookups in tables, such as the HashTable class, and other kinds of
collections.
A hash table uses the hash code to drastically limit the number of objects that
must be searched to find a specific object in a collection of objects. The hash
table does this by getting the hash value of the object and eliminating all objects
with a different hash code. This preliminary search leaves only those objects
with the same hash code to be searched. Because there are few instances with
that hash code, searches are much quicker.
System.Object provides a GetHashCode method, which returns an int type.
You should override this method to return a hash code on any custom classes or
structures that you create. One reason for overriding this method is that when
two objects are equal in value, you should get the same hash code for each
object if you call GetHashCode. In the case of custom objects, the default
implementation of GetHashCode does not give you the same hash code for two
objects that are equal in value.
Topic Objective
To explain how to use hash
codes to perform quick
lookups in tables and other
types of collections.
Lead-in
A hash function is used to

quickly generate a number,
or hash code, that
corresponds to the value of
an object.
4 Module 6: Working with Types


A good hash code algorithm will support the best performance by generating a
random distribution for all input. You should base your hash code algorithm on
one of the unique fields in the class. Also, you should never throw an exception
from the GetHashCode method because GetHashCode can be called
frequently and should always work reliably.
The following example shows how to implement GetHashCode for a Student
structure that stores a student’s name and ID.
struct Student
{
string name;
int ID; //Unique for each instance
public override int GetHashCode()
{
return ID;
}
}

Module 6: Working with Types 5


Identity
!
Compare to Determine If Two References Are Actually

the Same Object
!
Use the Object.ReferenceEquals Method to Test Identity

*****************************
ILLEGAL FOR NON
-
TRAINER USE
******************************
There are two kinds of comparison for objects: identity and equality. This topic
covers object identity.
Determining Identity
Two objects are identical if they are, in fact, the same object. Every object in
the .NET Framework common language runtime has an identity that makes it
unique in the system.
In C++, an object’s identity is determined by its address. Thus, if two pointers
are compared and contain the same address, they point to the same object.
In COM, an object’s identity is determined by the IUnknown interface. Thus, if
two IUnknown interface pointers are compared and contain the same address,
they are the same COM object.
In the .NET Framework common language runtime, you can use the
Object.ReferenceEquals method to compare for identity. Internally,
ReferenceEquals compares the addresses of the objects in memory to
determine if they are the same object. If they are the same object,
ReferenceEquals returns true.
Topic Objective
To explain how identity is
determined in the .NET
Framework common
language runtime.

Lead-in
There are two kinds of
comparison for objects:
identity and equality. This
topic covers object identity.
6 Module 6: Working with Types


Using the Object.ReferenceEquals Method
In the following example, a value type variable called x is created and passed in
two parameters to the Test method. The Test method compares the two
parameters to determine if they are identical.
class MyObject
{
public int X;
}

class MainClass
{
public static void Main()
{
MyObject obj1 = new MyObject();
obj1.X = 5;
Test(obj1, obj1);
MyObject obj2 = new MyObject();
obj2.X = 5;
Test(obj1, obj2);
}
public static void Test(MyObject a, MyObject b)
{

if (Object.ReferenceEquals(a,b))
Console.WriteLine("Identical");
else
Console.WriteLine("Not Identical");
}
}

This code generates the following output:
Identical
Not Identical

Module 6: Working with Types 7


Equality
!
Comparing Two Objects to Determine If They Are Equal
!
Override the Equals Method
!
Supply == and != Operators
!
Guidelines
#
If overriding Equals, override GetHashCode
#
If overloading ==, override Equals to use same
algorithm
#
If implementing IComparable, implement Equals

#
Equals, GetHashCode, and == operator should never
throw exceptions

*****************************
ILLEGAL FOR NON
-
TRAINER USE
******************************
Objects can also be compared for equality. The Object.Equals method,
equality operator (==), or inequality operator (!=) are used to test equality.
Equals Method
The Equals method is part of the Object class. You should override this
method in your classes and structures to perform appropriate behavior when
comparing objects of certain types. The default Object.Equals method calls
Object.ReferenceEquals, which results in an identity comparison instead of a
value comparison. In general, you should also override the == and != operators
to allow easier syntax to compare objects.
Topic Objective
To explain how to override
the Equals method and to
introduce guidelines for
implementing code to
provide equality comparison
for types.
Lead-in
Objects can also be
compared for equality.
8 Module 6: Working with Types



The following example shows how to override the Equals method and the ==
and != operators to test user-defined Rectangle objects for equality.
class Rectangle
{
//Rectangle coordinates
public int x1,y1,x2,y2;
public Rectangle(int x1, int y1, int x2, int y2)
{
this.x1 = x1;
this.x2 = x2;
this.y1 = y1;
this.y2 = y2;
}
public override int GetHashCode()
{
return x1;
}
public override bool Equals (Object obj)
{
//Check for null and compare run-time types.
if (obj == null || GetType() != obj.GetType()) return
false;
Rectangle r = (Rectangle)obj;
return (x1 == r.x1) && (y1 == r.y1) && (x2 == r.x2) &&
(y2 == r.y2);
}
static public bool operator == (Rectangle r1, Rectangle r2)
{
//Check for null parameters

//Cast to object to avoid recursive call
if ((object)r1 == null) return false;
//Let Equals method handle comparison
return r1.Equals(r2);
}
static public bool operator != (Rectangle r1, Rectangle r2)
{
//Check for null parameters
//Cast to object to avoid recursive call
if ((object)r1 == null) return true;
//Let Equals method handle comparison
return !r1.Equals(r2);
}
}

class MainClass
{
public static void Main()
{
Rectangle r1 = new Rectangle(5,5,50,55);
Rectangle r2 = new Rectangle(5,5,50,55);
Console.WriteLine(r1.Equals(r2));
Console.WriteLine(r1 == r2);
Console.WriteLine(null == r1);
}
}
Module 6: Working with Types 9


This code generates the following output:

True
True
False

Guidelines for Equality Comparison
Use the following guidelines when implementing code to provide equality
comparison for types.
!
Anytime you override the Equals method, also override the GetHashCode
method. If two objects are equal, they must return the same hash code. The
default implementation of GetHashCode does not return the same value.
!
Anytime you overload the == operator, also override the Equals method
and the != operator to use the same algorithm. This technique allows
infrastructure code, such as HashTable and ArrayList classes, that uses the
Equals method, to behave in the same manner as user code that is written
with the == operator.
!
Anytime you implement the IComparable interface, also implement the
Equals method, and ensure that both elements use the same algorithm for
comparisons. You should also consider overloading the comparison
operators because any client code that uses the IComparable interface is
also likely to use these operators.
!
The Equals method, GetHashCode method, and comparison operators
should never throw an exception. Exceptions in comparison operators can
cause confusion because most programmers do not anticipate these types of
exceptions. Also, these methods are called frequently and need to be
efficient and clean to avoid writing additional error-handling code for what
are considered simplistic methods.


10 Module 6: Working with Types


String Representation
!
Override ToString to Customize String Form of a Class
!
Use IFormattable Interface and ToString Method for
Localized Strings
struct President
{
public string FirstName;
public string LastName;
public override string ToString()
{
return FirstName + " " + LastName;
}
}
struct President
{
public string FirstName;
public string LastName;
public override string ToString()
{
return FirstName + " " + LastName;
}
}

*****************************

ILLEGAL FOR NON
-
TRAINER USE
******************************
One characteristic of all objects is the ability to represent themselves in a string
form. The ToString method provides this ability for all objects. Methods in the
Microsoft .NET Framework common language runtime, such as
Console.WriteLine, frequently use ToString. The ToString method also is
useful for debugging.
The default behavior of the Object.ToString method is to return the name of
the class. The following example shows what happens when ToString is called
on a President structure.
struct President
{
public string FirstName;
public string LastName;
}
class MainClass
{
public static void Main()
{
President firstPres;
firstPres.FirstName = "George";
firstPres.LastName = "Washington";
Console.WriteLine(firstPres.ToString());
}
}

This code generates the following output:
President


Topic Objective
To explain how the
ToString method is used in
the .NET Framework
common language runtime.
Lead-in
All objects have the ability to
represent themselves in a
string form.
Module 6: Working with Types 11


You can override the ToString method to provide custom behavior, as shown
in the following example:
struct President
{
public string FirstName;
public string LastName;
public override string ToString()
{
return FirstName + " " + LastName;
}
}
class MainClass
{
public static void Main()
{
President firstPres;
firstPres.FirstName = "George";

firstPres.LastName = "Washington";
Console.WriteLine(firstPres.ToString());
}
}

This code generates the following output:
George Washington

If an object needs to be represented in localized string forms, you should not
override Object.ToString. Instead, you should implement the IFormattable
interface and its ToString method. The IFormattable interface can take into
account different locales.
12 Module 6: Working with Types


"
""
"

Specialized Constructors
!
Static Constructors
!
Private Constructors

*****************************
ILLEGAL FOR NON
-
TRAINER USE
******************************

This section covers more advanced types of constructors. It explains how static
constructors work, when to use them, and when to use private constructors.
Topic Objective
To provide an overview of
the topics covered in this
section.
Lead-in
This section covers more
advanced types of
constructors. It explains how
static constructors work,
when to use them, and
when to use private
constructors.
Module 6: Working with Types 13


Static Constructors
!
Used to Initialize Static Members
!
.cctor in Disassembly
class DeviceConnection
{ public static uint ConnectionCount;
public void OpenConnection(string connectionName)
{ ConnectionCount++;
//Other work to open device }
static DeviceConnection()
{ //Initialize static members
ConnectionCount = 0; }

}
class DeviceConnection
{ public static uint ConnectionCount;
public void OpenConnection(string connectionName)
{ ConnectionCount++;
//Other work to open device }
static DeviceConnection()
{ //Initialize static members
ConnectionCount = 0; }
}

*****************************
ILLEGAL FOR NON
-
TRAINER USE
******************************
Static constructors are used to initialize static fields. Static constructors are also
known as class constructors and type constructors. Static constructors are called
after a program begins running but before the first instance of the class is
created.
Topic Objective
To explain how static
constructors work.
Lead-in
Static constructors are used
to initialize static fields.
14 Module 6: Working with Types


The following example shows a DeviceConnection class that represents a

generic connection to a device. The class maintains a static field that holds the
current connection count. The static constructor is created with the same name
as the class but has the static attribute, rather than the public or private
attribute.
class DeviceConnection
{
public static uint ConnectionCount;
public void OpenConnection(string connectionName)
{
ConnectionCount++;
//Other work to open device
}
static DeviceConnection()
{
//Initialize static members
ConnectionCount = 0;
}
}

class MainClass
{
public static void Main()
{
// At some point before next line,
// static constructor is called
DeviceConnection d = new DeviceConnection();
d.OpenConnection("GameConsole:Joy1/3");
// Next line prints 1
Console.WriteLine(DeviceConnection.ConnectionCount);
}

}

A static constructor has no access modifiers, such as private or public. Inside a
static constructor, only static fields can be used. Instance fields must be
initialized in an instance constructor.
When the static constructor is viewed in disassembly, it has a different name,
.cctor, which stands for class constructor. In disassembly, instance constructors
are called .ctor. You can have both types of constructors in the same class.
Module 6: Working with Types 15


If you initialize a static field inline with a value, a static constructor is created
automatically. The following example shows how the DeviceConnection class
can be rewritten to use an implicit static constructor. The presence of the static
constructor can be verified by viewing the disassembly of the code.
class DeviceConnection
{
//Next line automatically creates static constructor
public static uint ConnectionCount = 0;
public void OpenConnection(string connectionName)
{
ConnectionCount++;
//Other work to open device
}
}

In the preceding example, the static field ConnectionCount is initialized inline
to a value of 0. When you initialize static fields inline, a static constructor is
implicitly created in which the initialization occurs. If you also provide an
explicit static constructor, the inline initialization is compiled into the explicit

static constructors. Inside the static constructor, the code for the inline
initializations runs first, and then the code that you wrote in the static
constructor runs.

×