Should Implement Efficient Algorithm struct Student {string name; int ID; //Unique for each instancepublic override int GetHashCode {return ID; }} struct Student {string name; int ID; //
Trang 1Lab 6: Working with Types 38
Review 43
Module 6:
Working with Types
Trang 2Information 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
Trang 3Instructor 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
Trang 4Module 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
Trang 5! 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
In this module, you will learn
how to apply your
knowledge of the Common
Type System to various
programming scenarios
Trang 6" 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
In this section, you will learn
about the common methods
that you need to override on
the System.Object class
Trang 7Hash 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 instancepublic override int GetHashCode() {return ID;
}}
struct Student {string name;
int ID; //Unique for each instancepublic 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
Trang 8A 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;
} }
Trang 9Identity
! 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
Trang 10Using 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();
if (Object.ReferenceEquals(a,b)) Console.WriteLine("Identical");
else Console.WriteLine("Not Identical");
} } This code generates the following output:
Identical Not Identical
Trang 11Equality
! 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
Trang 12The 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) {
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);
} }
Trang 13This 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
Trang 14String 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
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
Trang 15You 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() {
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
Trang 16" 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
constructors It explains how
static constructors work,
when to use them, and
when to use private
constructors
Trang 17Static 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 membersConnectionCount = 0; }}
class DeviceConnection{ public static uint ConnectionCount;
public void OpenConnection(string connectionName){ ConnectionCount++;
//Other work to open device }static DeviceConnection()
{ //Initialize static membersConnectionCount = 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
Trang 18The 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
Trang 19If 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
Trang 20Private Constructors
! Prevent a Class from Being Instantiated
! Use Them on Classes with All Static Members
! Use a Protected Constructor to Inherit from the Class
class Trig{
public static double Sin (double x){ //Calculate and return sin(x) }public static double Cos (double x){ //Calculate and return cos(x) }public static double Tan (double x){ //Calculate and return tan(x) }private Trig(){}
}
class Trig{
public static double Sin (double x){ //Calculate and return sin(x) }public static double Cos (double x){ //Calculate and return cos(x) }public static double Tan (double x){ //Calculate and return tan(x) }private Trig(){}
}
***************************** ILLEGAL FOR NON - TRAINER USE ******************************
A private constructor can never be called Therefore any class with a private
constructor cannot be instantiated The only type of class that uses a private constructor is a class with all static members
The following example shows how a private constructor is used to prevent a class from being instantiated
class Trig {
public static double Sin (double x) {
//Calculate and return sin(x) }
public static double Cos (double x) {
//Calculate and return cos(x) }
public static double Tan (double x) {
//Calculate and return tan(x) }
A private constructor can
never be called Therefore
any class with a private
constructor cannot be
instantiated
Trang 21Classes with all static members can be used to maintain global algorithms, as shown in the preceding example They can also be used as a singleton class, which has only one set of values and methods that is available while a program
is running
To derive from a class with static members, you should mark the constructor as protected Marking the constructor as protected will prevent programmers from creating instances of the class, but allow other classes to derive from it
A class with static members is different than an interface The static members can contain implementations, a class can have static fields, but an interface cannot
Note
Trang 22" Type Operations
! Conversions
! Casting
! Boxing
***************************** ILLEGAL FOR NON - TRAINER USE ******************************
The NET Framework common language runtime supports a variety of type operations for working with types This section discusses conversions and conversion operators for determining and converting the type of an object This section also discusses how to cast types for conversion and for treating a type as
a different type It also describes boxing and unboxing value types to treat them
The NET Framework
common language runtime
supports a variety of type
operations for working with
types
Trang 23***************************** ILLEGAL FOR NON - TRAINER USE ******************************
Conversion is the process of changing a type to another type Conversions are
necessary when a value of one type must be assigned to a variable of a different type during assignment or when passing arguments to a method call
Explicit and Implicit Conversions
In explicit conversions, you do not need to specify the name of the type in a cast
for assignment conversions or operand conversions
The following example shows how to convert an int value to a double value by
using an explicit conversion
public static bool BiggerThanFive(double value) {
if (value > 5) return true;
else return false;
} public static void Main() {
an int is 32 bits, and the bit size of a double is 64 bits Therefore, the type was
widened during the conversion
Topic Objective
To explain when and how
to use explicit and implicit
Trang 24In implicit conversions, you do not need to specify the name of the type during
the conversion Widening conversions can occur implicitly, and so they allow for simpler syntax The preceding example could be written more simply as follows:
public static void Main() {
in the common language runtime
From To sbyte short, int, long, float, double, or decimal byte short , ushort, int, uint, long, ulong, float, double, or decimal short int, long, float, double, or decimal
ushort int, uint, long, ulong, float, double, or decimal int long, float, double, or decimal
uint long, ulong, float, double, or decimal long float, double, or decimal
char ushort, int, uint, long, ulong, float, double, or decimal float double
ulong float, double, or decimal
Some conversions can result in a loss of precision For example, converting an
int to a float is an allowable implicit conversion, but a float has only seven
digits of precision Depending on the value of the int, some digits of precision