Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C# ПІДРУЧНИКИ / c# / Manning - Windows.forms.programming.with.c#.pdf
Скачиваний:
108
Добавлен:
12.02.2016
Размер:
14.98 Mб
Скачать

.NET Table 5.3 Object class

The Object class is the base class for all objects in C#, including the built-in types such as int and bool, and is part of the System namespace. The System.Object class is equivalent to the C# language object class in the .NET Framework.

Public Static

Equals

Determines if two objects are equal.

ReferenceEquals

Determines if two objects both refer to the same

Methods

 

 

object instance.

 

 

 

 

Equals

Determines whether a given object is the same as

 

 

this object. Performs bitwise equality for value

 

 

types, and object equality for reference types.

 

GetHashCode

Returns an integer suitable for use as a hash code

 

 

for the object. Objects which are equal (based on

 

 

the Equals method) return the same value, so you

Public Methods

 

should override this method if you override Equals.

 

 

 

GetType

Returns the Type object representing the C#

 

 

language metadata associated with the object.

 

ToString

Returns a string that represents the current

 

 

object. By default, the name of the object’s type is

 

 

returned, so classes should normally override this

 

 

method to return a more useful value.

 

 

 

In order to ensure that Photographs compare as expected, we must override the Equals method. Our override will return true if the two photos refer to the same file.

 

 

OVERRIDE EQUALS METHOD

 

 

 

 

Action

Result

 

 

 

1

In the Photograph.cs file,

public override bool Equals(object obj)

 

provide an override of the

{

 

Equals method that

if (obj is Photograph)

 

{

 

compares file names.

 

Photograph p = (Photograph)obj;

 

 

return (_fileName.ToLower().

 

 

Equals(p.FileName.ToLower()));

 

 

}

 

 

return false;

 

 

}

 

 

 

Some features of this code are worth noting in more detail:

1In C#, the override keyword is required to override a virtual method. Using the virtual keyword here would cause a compile error, since the method name is already declared in the base class. The override keyword indicates that the

Equals method here serves the same purpose as the inherited member and replaces this base member. To define a new meaning for an inherited member and hide the original definition, the new modifier is used instead of the override keyword.

ROBUSTNESS ISSUES

155

public override bool Equals(object obj)

{

2Since we must handle any object here, we only perform our comparison if the given object is a Photograph. We use the is keyword for this purpose, even though this results in the performance of two cast operations—one for the is keyword, and one for the actual cast.

if (obj is Photograph)

{

Photograph p = (Photograph)obj;

3The String.Equals method performs a case-sensitive comparison of strings. That is, “book” and “book” are equal, but “book” and “Book” are not. To ignore capitalization in our file name strings, we use the ToLower method to make sure the compared strings are all lower case.

return (_fileName.ToLower().Equals(p.FileName.ToLower()));

}

4 Note how false will always be returned if the given object is not a Photograph.

return false;

}

It is also worth noting here that the String class overrides the Equals method to perform a value-based case-sensitive comparison of its contents, even though it is a reference type. This ensures that two String objects are identical as long as they contain the same set of characters in the same order.

We should also override the GetHashCode and ToString methods in our Photograph class. The default GetHashCode implementation for the Object class returns different hash values for different references, while the default ToString implementation returns the name of the type, in this case the string "Photograph". Neither of these implementations really works for our purposes.

This is especially true for the GetHashCode method. This method should return an identical value for identical, or equal, objects. The default implementation for reference types works fine when two physically different objects are never equal. In our case, since two different photographs can now be equal, this means that two Photograph objects that refer to the same file name might return different hash values.3 This would make it rather difficult to look up Photograph objects in a hash table. As a

3This discussion assumes you understand hashing and hash tables. Briefly, a standard hash table uses a key, or hash code, as an index into a table. Unlike an array, this key does not have to be unique for each object, since each entry in the table refers to a linked list of objects that hash to the same key. A hash table enjoys the benefits of a linked list in that items can be quickly inserted and removed, and the benefits of an array since items can be quickly located. Of course, it all depends on a table appropriate for the number of expected items, and a good hash code algorithm that produces an equal distribution of values for the stored data across the entire table.

156

CHAPTER 5 REUSABLE LIBRARIES

rule, you should always (yes, always!) override GetHashCode if you are overriding the Equals method. In our case, the comparison in Equals is based on the file name string, so we can use the String.GetHashCode method in a similar fashion.

OVERRIDE THE GETHASHCODE METHOD

 

Action

Result

 

 

 

2

Override the GetHashCode method.

public override int GetHashCode()

 

How-to

{

 

return this.FileName.GetHashCode();

 

Use the String.GetHashCode

}

 

method on the contained file name.

 

 

 

 

Finally, we may as well override the ToString method here as well. The default implementation will return the string "Photograph" every time, which is not very illuminating. A better implementation for our purposes would return the file name associated with the photograph, which is what we will do here.

OVERRIDE THE TOSTRING METHOD

 

Action

Result

 

 

 

3

Override the ToString method to

public override string ToString()

 

return the contained file name.

{

 

 

return this.FileName;

 

 

}

 

 

 

Compile the code to verify that you and I have not made any errors. These overrides of the base Object methods will come in useful in future chapters. Since they are found in every object, Windows Forms controls make use of these methods whenever an object must be compared with another object or a corresponding string displayed in a window. In particular, we will see in chapter 10 how list controls utilize the ToString method by default when displaying an object in a list. As a result, providing a reasonable ToString implementation for your classes is always a good idea.

The changes in this section ensure that the base object methods are properly implemented for our Photograph class. Another change we should make is to ensure that any system resources used by our classes are cleaned up as required.

5.4.3DISPOSING OF RESOURCES

Our PhotoAlbum and Photograph classes are now fairly well-defined. We can create photographs from image files, add and remove photos to albums, and iterate through the contents of an album. A topic we haven’t touched on is the issue of cleaning up a photo or album when we are finished.

You might be wondering why we even care. Isn’t this the purpose of garbage collection? When we are finished with an album, the garbage collector will clean it up eventually, so we do not need to worry about it.

ROBUSTNESS ISSUES

157

PhotoAl-

This is true to a point. The problem is that we have no idea when the garbage collector will run. It could be immediately, it could be hours later, or it could even be in conjunction with the program exiting. This is fine for the memory used by our objects, but might present a problem for the system resources in use. For example, the creation of a Bitmap object requires that a file be opened and loaded into memory. This requires file and other system resources. Since such resources can be limited, it is a good idea to release them when you are finished.

The preferred method for doing this is through a Dispose method as part of the IDisposable interface. This interface is summarized in .NET Table 5.4. Since the Component class supports the IDisposable interface and is the basis for most classes in the System.Windows.Forms namespace, most objects in the Windows Forms namespace provide a Dispose method for just this purpose.

.NET Table 5.4 IDisposable interface

The IDisposable interface indicates that an object can be disposed of. Typically, instances of objects that support this interface should always call the Dispose method to free any nonmemory resources before the last reference to the object is discarded. This interface is part of the System namespace.

Public Methods

Dispose

Releases any resources used by the object.

 

 

 

Let’s support this interface in our classes. In many cases, it is an error to reference a disposed object. In our case, we would like to be able to clear and reuse a

bum instance, so we will leave the album object in a usable state after the Dispose method has been called.

SUPPORT THE IDISPOSABLE INTERFACE

 

Action

Result

 

 

 

1

In the Photograph.cs source file,

public class Photograph : IDisposable

 

indicate that this class will support

{

 

the IDisposable interface.

. . .

 

 

 

 

 

2

Implement the Dispose method.

public void Dispose()

 

How-to

{

 

if (_bitmap != null

 

Dispose of the contained bitmap

&& _bitmap != InvalidPhotoImage)

 

only if it exists and is not our static

{

 

InvalidPhotoImage bitmap.

_bitmap.Dispose();

 

}

 

 

 

 

_bitmap = null;

 

 

}

 

 

. . .

 

 

}

 

 

 

3

Similarly, support the IDisposable

public class PhotoAlbum :

 

interface in the PhotoAlbum.cs file.

CollectionBase, IDisposable

 

 

{

 

 

. . .

 

 

 

158

CHAPTER 5 REUSABLE LIBRARIES

Соседние файлы в папке c#