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

5.4ROBUSTNESS ISSUES

While our classes are basically ready, there are some additional issues that will affect the robustness of our application in future chapters. This section will address a number of these issues in order to make our library a bit more sturdy. These topics apply more generally to any class library, so are probably worth considering while developing your own libraries as well.

This section will look at the following areas:

Handling the potential exception when a bitmap is created.

Ensuring that photographs are compared as expected.

Cleaning up system resources used by our classes.

Associating a file name with an album.

We will examine each issue separately.

5.4.1HANDLING AN INVALID BITMAP

We discussed the concept of exceptions in chapter 2. Here, there is a potential exception when we create our Bitmap object for the Image property. Look back at our definition of this property.

public Bitmap Image

{

get

{

if (_bitmap == null)

{

_bitmap = new Bitmap(_fileName);

}

return _bitmap;

}

}

If the file is an invalid bitmap, or cannot be loaded for some reason, this presents a real problem. On the one hand, this is an error, so perhaps we should return null or allow the exception to be thrown. On the other hand, the caller is expecting to display a Bitmap, and checking for null or an exception every time seems a bit cumbersome, not to mention the issue of what the caller should then display in lieu of a Bitmap object.

As an alternative approach, we will instead create a special bitmap to return whenever the file cannot be loaded. This provides a Bitmap that the caller can display in any situation, but still indicates that something is wrong. We will create a private static member of our Photograph class to hold this special image, and provide a new property to indicate if a valid image for the current Photograph exists.

Let’s see how this looks.

ROBUSTNESS ISSUES

151

Invalid-

Set the version number of the MyPhotoAlbum library to 5.4.

 

 

HANDLE THE BITMAP EXCEPTION

 

 

 

 

 

Action

 

Result

 

 

 

 

1

In the Photograph.cs file,

 

private static Bitmap _invalidImageBitmap

 

create a private static

 

= null;

 

member to hold a Bitmap

 

 

 

object.

 

 

 

 

 

 

2

Add a public property to

 

public static Bitmap InvalidPhotoImage

 

retrieve this bitmap.

 

{

 

How-to

 

get

 

 

{

 

Create a 100×100 pixel

 

if (_invalidImageBitmap == null)

 

image that contains a red X

 

{

 

 

// Create the "bad photo" bitmap

 

to indicate it is invalid.

 

 

 

Bitmap bm = new Bitmap(100, 100);

 

 

 

Graphics g = Graphics.FromImage(bm);

 

 

 

g.Clear(Color.WhiteSmoke);

 

 

 

// Draw a red X

 

 

 

Pen p = new Pen(Color.Red, 5);

 

 

 

g.DrawLine(p, 0, 0, 100, 100);

 

 

 

g.DrawLine(p, 100, 0, 0, 100);

 

 

 

_invalidImageBitmap = bm;

 

 

 

}

 

 

 

return _invalidImageBitmap;

 

 

 

}

 

 

 

}

 

 

 

 

3

Use this new property as

 

public Bitmap Image

 

the bitmap to return if the

 

{

 

image file cannot be

 

get

 

 

{

 

loaded.

 

 

 

if (_bitmap == null)

 

 

 

{

 

 

 

try

 

 

 

{

 

 

 

_bitmap = new Bitmap(_fileName);

 

 

 

}

 

 

 

catch

 

 

 

{

 

 

 

_bitmap = InvalidPhotoImage;

 

 

 

}

 

 

 

}

 

 

 

return _bitmap;

 

 

 

}

 

 

 

}

 

 

 

 

4

Also add a new property

 

public bool IsImageValid

 

IsImageValid to identify

 

{

 

if a valid image file is

 

get

 

 

{

 

present.

 

 

 

return (_bitmap != InvalidPhotoImage);

 

 

 

}

 

 

 

}

 

 

 

 

There is quite a bit of new code here (at least, by our standards in this chapter), so let’s take a look at some of the more important pieces. First, look at the

PhotoImage property.

152

CHAPTER 5 REUSABLE LIBRARIES

_bitmap

public static Bitmap InvalidImageBitmap

{

get

{

if (_invalidImageBitmap == null)

{

// Create the "bad photo" bitmap Bitmap bm = new Bitmap(100, 100);

Graphics g = Graphics.FromImage(bm); g.Clear(Color.WhiteSmoke);

b Create the new bitmap

c Construct Graphics object

Pen p = new Pen(Color.Red, 5);

 

d Draw a red X

 

g.DrawLine(p,

0, 0,

100, 100);

 

 

g.DrawLine(p,

100, 0,

0, 100);

 

 

_invalidImageBitmap

=

bm;

 

 

}

return _invalidImageBitmap;

}

}

The get implementation shown here creates and initializes the _invalidImageBitmap object the first time the property is invoked.

b First, a new Bitmap of size 100×100 pixels is constructed.

cNext, a Graphics object is generated to treat the Bitmap as a drawing surface using the static Graphics.FromImage method.

dFinally, a new red Pen is constructed with a width of five pixels and two lines are drawn corner to corner on the bitmap image to create a big red X. The Pen class is part of the System.Drawing namespace discussed in chapter 4. We could have used the Pen object returned by the Red property of the Pens class. This pen has a width of one pixel, so we opted to create our own pen instead.

Since the _invalidImageBitmap member variable is static, this code is executed the first time the property is called, and the image is then re-used as needed for all

PhotoAlbum objects in the application. In the Photograph.Image property, an exception raised while creating the bitmap is caught and the field is set to our invalid image.

try

{

_bitmap = new Bitmap(_fileName);

}

catch

{

_bitmap = InvalidImageBitmap;

}

Notice how an exception class is not specified in the catch clause. This ensures that all exceptions will be caught regardless of their origin.

ROBUSTNESS ISSUES

153

Finally, a new IsImageValid property compares the photo’s bitmap to the static invalid image variable to see if they are equal. If they are, then the original photo is not a valid photograph.

public bool IsImageValid

{

get

{

return (_bitmap != InvalidPhotoImage);

}

}

Interestingly enough, if neither the _bitmap nor the _invalidImageBitmap variables has been initialized, then this comparison will generate both Bitmap objects in order to compare them.

This handles any possible exception our code might encounter when creating a bitmap from a given file name. One other subtle but very important change we need to make is how Photograph objects are compared. We will take this up next.

5.4.2OVERRIDING METHODS IN THE OBJECT CLASS

As we have repeatedly indicated, all classes in C# implicitly inherit from the object class, which is the same as System.Object class. In this section we look at the Object class in some detail, and override some of the methods inherited from this class in our Photograph class.

You may wonder why there is both an object and an Object, and the answer is both simple and confusing. The object class is part of the C# language definition, and all types, be they built-in or specific to your program, ultimately inherit from object.

Separate from the language definition is the .NET Framework, containing classes

and namespaces used to generate programs and services of every kind. Within the

.NET Framework is the System.Object class. In Microsoft’s C# compiler, the System.Object class is equivalent to the C# object class. So object and Object are different but functionally equivalent. In this book, we have used and will continue to use both classes interchangeably, with a preference toward the language-specific object. An overview of the Object class is shown in .NET Table 5.3.

Note that a similar discussion applies to the classes string and System.String as well.

Look closely at the Equals method in the table. In our Photograph class, we would like two Photographs to be equal if they represent the same file. So far, however, this will not be the case. Since Photograph is a reference type, two objects will be equal only if they refer to the same physical storage on the heap. It doesn’t matter if both objects internally represent the same image file. If they are different references, they are not equal. This behavior should come as no surprise to the seasoned Java coders among us, but might seem a little strange to programmers accustomed to C++ or Visual Basic behavior.

154

CHAPTER 5 REUSABLE LIBRARIES

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