
C# ПІДРУЧНИКИ / c# / MS Press - Msdn Training Programming Net Framework With C#
.pdfModule 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
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.
! Override ToString to Customize String Form of a Class
struct President struct President
{{ public string FirstName; public string FirstName; public string LastName; public string LastName;
public override string ToString() public override string ToString()
{{
return FirstName + " " + LastName; return FirstName + " " + LastName;
}}
}}
!Use IFormattable Interface and ToString Method for Localized Strings
*****************************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
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
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.
!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.

Module 6: Working with Types |
13 |
|
|
|
|
Static Constructors
Topic Objective
To explain how static constructors work.
Lead-in
Static constructors are used to initialize static fields.
! Used to Initialize Static Members
|
class DeviceConnection |
|
|
|
|
||
|
class DeviceConnection |
|
|
|
{ public static uint ConnectionCount; |
|
|
|
{ public static uint ConnectionCount; |
|
|
|
public void OpenConnection(string connectionName) |
|
|
|
public void OpenConnection(string connectionName) |
|
|
|
{ |
ConnectionCount++; |
|
|
{ |
ConnectionCount++; |
|
|
|
//Other work to open device } |
|
|
|
//Other work to open device } |
|
|
static DeviceConnection() |
|
|
|
static DeviceConnection() |
|
|
|
{ |
//Initialize static members |
|
|
{ |
//Initialize static members |
|
|
|
ConnectionCount = 0; } |
|
|
}} |
ConnectionCount = 0; } |
|
|
|
|
! .cctor in Disassembly
*****************************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.
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.

16 |
Module 6: Working with Types |
Private Constructors
Topic Objective
To explain when to use private constructors.
Lead-in
A private constructor can never be called. Therefore any class with a private constructor cannot be instantiated.
!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 class Trig
{{ public static double Sin (double x) public static double Sin (double x) { //Calculate and return sin(x) }
{ //Calculate and return sin(x) } public static double Cos (double x) public static double Cos (double x) { //Calculate and return cos(x) }
{ //Calculate and return cos(x) } public static double Tan (double x) public static double Tan (double x) { //Calculate and return tan(x) }
{ //Calculate and return tan(x) } private Trig(){}
}}
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)
}
private Trig(){}
}

Module 6: Working with Types |
17 |
|
|
|
|
Classes 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.
Note 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.

18 |
Module 6: Working with Types |
" Type Operations
Topic Objective
To provide an overview of the topics covered in this section.
Lead-in
The .NET Framework common language runtime supports a variety of type operations for working with types.
!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 as reference types.