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

this we will need more than a single photograph in our application. If we can display one, why not more than one. Let’s display multiple photos. We will call this, of course, a photo album.

To keep this chapter somewhat manageable, we will not muck with our main application window here. We will focus instead on creating a photo album abstraction, and wait until chapter 6 to integrate it into our application. Specifically, we will perform the following tasks in this chapter:

Create a PhotoAlbum class to represent a collection of photograph files.

Create a Photograph class to represent a single photograph.

Compile the PhotoAlbum and Photograph classes into an external library.

Before we write any code for these classes, a short design discussion is in order.

5.1C# CLASSES AND INTERFACES

Within our application, we need to represent the album in a way that facilitates the required actions, such as “add an image,” “move to the next photo,” and so forth. You may immediately think of some sort of array, and this will be our approach. This section will present a short design discussion as a way to introduce some terminology we require and lay the groundwork for writing our code.

Each photo is an image file located somewhere on disk. While a simple list of files could be stored in an array of strings, we should not be too hasty here. Requirements change, as do applications. We may want to add additional features to our photo album later, so it makes sense to encapsulate our album in a class to make this possible. Classes in C# are very similar to classes in the C++ and Java languages. We will create a PhotoAlbum class to represent a single photo album, and provide a set of methods that external users of the class, such as our MyPhotos application, can use to retrieve and modify the contents of the album.

What will our album contain? We already mentioned the idea of array file names. Since we would like to provide quick access to the images, we could also consider an array of Bitmap objects. Not a bad idea, except that a bitmap can be pretty large. A full color image such as a photograph uses 24 bits, or three bytes per pixel: one each for a red, blue, and green color. Do the math and you’ll find that a 640×480 pixel image takes up around 900K in memory, or almost 1 MB. A system with 32 MB of RAM will run out of memory fairly quickly, and even 128 or 256 MB systems will feel the pinch. Of course, virtual memory will allow us to use more than the available physical memory, but the performance will not make our users happy. Instead of bitmaps, we will stick with the file names of our images, and create Bitmap objects as required. To accommodate both types of information, and to extend this definition in the future, we will create a Photograph class to encapsulate the concept of a single photograph. Our album will contain zero or more photographs.

One more feature here: once we build our PhotoAlbum and Photograph classes, they could be useful in other programs that wish to use our concept of a photo

C# CLASSES AND INTERFACES

127

album. For example, a genealogy program for creating family trees might want to link to a photo album of a specific person or family. So we will place our new classes in a library that other programs can reuse. In Windows parlance, such a library is called a Dynamic Link Library, or DLL.

5.1.1INTERFACES

As you might expect, the .NET Framework provides a number of classes that can help us here. These classes implement common data structures such as arrays, stacks, queues, and hash tables. Before the ever-appropriate table summarizing such classes, this is a good place to introduce the idea of an interface.

An interface is an abstraction of an abstraction, and should be familiar to programmers of COM or its UNIX ancestor, the distributed computing environment (DCE). While a class encapsulates a data structure and its operations, an interface encapsulates a type of data structure and its operations. This is very similar to an abstract class, except that an interface does not provide any implementations for its members, it just defines the properties, methods, and events that a class should implement in order to support the interface. In practice, an interface is a good way to encapsulate a common idea for use by a number of possibly unrelated classes, while an abstract class is a good way to encapsulate a common idea for use by a number of related classes.

For example, the .NET ICloneable interface defines a type of class that can be cloned, or copied, from an existing class instance to a new one.1 This concept applies to the Array, Brush, Font, String, and a number of other classes throughout the

.NET Framework. Languages such as C++ provide multiple inheritance for this type of support. In C++, ICloneable could be an abstract class and inherited where needed. In C# and Java, only single inheritance is supported, so this is not possible. Instead, both languages provide interfaces as a way to encapsulate common functionality that can be used by a wide range of classes.

For example, the Brush class supports the ICloneable interface. We used this abstract class in chapter 4 to create an owner-drawn status bar panel. Brush objects can be cloned to create a new copy of an existing Brush. You can create an instance of a Brush, since it is a class, but you cannot create an instance of an ICloneable except as a by-product of an existing class that happens to support this interface.

The .NET Framework provides interfaces for everything from enumerating members of a set to transferring data between applications. Some interfaces related to our current discussion on albums are listed in the following table.

1Generally speaking, cloning in .NET always produces a deep copy of an object, as we saw for the menu classes in chapter 3.

128

CHAPTER 5 REUSABLE LIBRARIES

Interfaces related to data collections

Interface

Description

Sample Members

 

 

 

 

Interface that supports the creation of

GetEnumerator method, which returns a

 

an enumerator class for iterating over

class that supports the IEnumerator

 

the elements in a collection.

interface.

IEnumerable

Usage

 

 

Supporting this interface allows the C#

 

 

foreach statement to be used with

 

 

instances of a class or structure.

 

 

 

 

 

Interface for stepping through the

Current property, to retrieve the current

 

elements in a collection.

element from the collection.

IEnumerator

 

MoveNext method, which advances to

 

the next element in the collection.

 

 

 

 

Reset method, which sets the

 

 

enumerator just before the first element.

 

 

 

 

An IEnumerable interface that

Count property, to retrieve the number

 

provides sizing and synchronization

of elements in the collection.

 

capabilities. This interface is the basis

SyncRoot property, to retrieve an object

 

for all collections in the .NET

 

for synchronizing multi-threaded access

ICollection

Framework.

to the collection.

 

 

 

 

CopyTo method, which copies the

 

 

elements in the collection into an Array

 

 

object.

 

 

 

 

An ICollection interface that

Item property, to support array-style

 

provides indexing of its elements.

indexing of elements using [brackets],

 

Usage

much like a [] override in C++.

 

 

 

Supporting this interface allows a class

Add method, which adds a new element

IList

or structure to be treated as an array.

to the collection.

 

This permits objects to be used as

Contains method, which determines if

 

targets of data bound controls, as

 

the collection contains a specific object.

 

discussed in chapter 17.

 

Remove method, to remove the element

 

 

 

 

from the collection at a given index value.

 

 

 

5.1.2DATA COLLECTION CLASSES

Looking over the interfaces in the table, the IList interface seems particularly appropriate for the task at hand. This allows elements to be added and removed from the collection, and supports array-style indexing. Some of the data collection classes in the .NET Framework are shown in the following table. Note, in particular, those classes in the table that support the IList interface.

C# CLASSES AND INTERFACES

129

Some .NET classes related to data collections

Class

Description

Interfaces supported

Array

The base class for all array objects.

 

This class is abstract.

ArrayList

A dynamically-sized array.

CollectionBase

An abstract class for creating a

 

strongly typed collection.

DataView

A customized view of a database

 

table.

Hashtable

A collection of values stored based on

 

a hash code of the value, called a key.

Queue

A FIFO queue; a first in, first out

 

collection of objects.

SortedList

A sorted collection of keys and values

 

accessible by both key and index.

StringCollection

A collection of string objects.

Stack

A LIFO queue; a last in, first out

 

collection of objects.

ICloneable, IList, ICollection, IEnumerable

ICloneable, IList,

ICollection, IEnumerable

IList, ICollection, IEnumerable

IList, ICollection, IEnumerable, and others

ICloneable, ICollection,

IEnumerable, IDictionary, and others

ICloneable, ICollection,

IEnumerable

ICloneable, ICollection,

IEnumerable, IDictionary

IList, ICollection,

IEnumerable

ICloneable, ICollection,

IEnumerable

Since we do not have a database here, the DataView class is not appropriate. If all we wanted was a collection of file names, the StringCollection class would work, but then our PhotoAlbum would not be very extensible. This leaves us with a simple array or the ArrayList or CollectionBase classes. A simple fixed-size array is not appropriate since we would like our album to grow dynamically. So we are left to choose between the ArrayList and CollectionBase classes.

Either class would work here, and both classes can be quite useful. An overview of the ArrayList class is shown in .NET Table 5.1. Deriving our PhotoAlbum class from ArrayList would look like this:

// Deriving PhotoAlbum from ArrayList (not our approach) public class PhotoAlbum : System.Collections.ArrayList

{

// Inherits all properties and methods from ArrayList

}

An advantage of this approach is that we would not need to implement many of the methods, since they would be directly inherited from ArrayList. A disadvantage is that all methods would accept any object, and not just our Photograph objects. If you look at the documentation, you will see that the methods in ArrayList operate on object instances. For example, the PhotoAlbum.Add method would have the following signature:

130

CHAPTER 5 REUSABLE LIBRARIES

// PhotoAlbum.Add when derived from ArrayList

public int Add( object value );

So while this would be a very easy implementation, the methods in our PhotoAlbum class would not be type-safe, and therefore not so robust.

.NET Table 5.1 ArrayList class

The ArrayList class is a collection of indexed objects where the number of objects can change dynamically. This class is part of the System.Collections namespace, and is very similar to the Array class for fixed-length collections of objects. The ArrayList class supports the ICloneable, IEnumerable, ICollection, and IList interfaces.

Public

Capacity

Gets or sets the maximum number of objects the list can contain.

Properties

Count

Gets or sets the actual number of objects in the array.

 

 

 

 

 

Add

Adds an object to the end of the array.

 

AddRange

Adds the elements from an ICollection interface to the end of

 

 

the array.

 

Clear

Removes all objects from the array.

 

Contains

Determines if an object is in the array. Comparison is done using

 

 

the Object.Equals method.

 

CopyTo

Copies the ArrayList, or a portion of it, into a one-dimensional

Public

 

Array object.

 

 

Methods

IndexOf

Returns the zero-based index of the first occurrence of the given

 

 

 

object in the array, or –1 if the object is not found. Comparison is

 

 

done using the Object.Equals method.

 

Remove

Removes an object from the array.

 

RemoveAt

Removes the object at a given index from the array.

 

Sort

Sorts the array, using an IComparable interface to compare

 

 

objects.

 

TrimToSize

Sets the capacity of the array to the actual number of objects in it.

 

 

 

Let’s instead take a look at the CollectionBase class. An overview of this class is shown in .NET Table 5.2. This class is an abstract class, and requires derived classes to implement the additional methods required to support the appropriate interfaces. This requires a little more work on our part, but creates a nicer interface that works with Photograph objects directly.

Before we create our implementation, note that an alternative implementation would incorporate a private ArrayList object in a class derived directly from System.Object. This alternative would look something like the following:

// PhotoAlbum implementation with private ArrayList (not our approach)

class PhotoAlbum

{

// internal (not inherited) ArrayList

C# CLASSES AND INTERFACES

131

private ArrayList _photoArray;

//Constructor and other wrappers

//Custom Add wrapper

public int Add(Photograph photo)

{

return _photoArray.Add(photo);

}

}

This would work just fine and be similar to our actual implementation derived from CollectionBase. Our implementation is more appropriate than this alternative, since the CollectionBase class is designed for just this purpose, and does in fact provide access to an ArrayList member through a protected property.

.NET Table 5.2 CollectionBase class

The CollectionBase class is an abstract class for creating strongly typed collections. A class is strongly typed if it only allows a specific type or types in its methods, rather than a generic type such as an object. Strongly typed classes allow the compiler to ensure that the proper objects are passed to methods in the class, and can prevent errors that would otherwise occur only at runtime.

The CollectionBase class is part of the System.Collections namespace. It supports the IEnumerable, ICollection, and IList interfaces. A complete list of the public members defined by this class is as follows. Derived classes must implement the additional methods to support the required interfaces.

Public

Count

Gets or sets the actual number of objects in the array.

Properties

 

 

 

 

 

 

Clear

Removes all objects from the array.

Public

GetEnumerator

Returns an enumerator that can iterate through the

 

elements in the collection using the IEnumerator

Methods

 

 

interface.

 

 

 

RemoveAt

Removes the object at a given index from the array.

 

 

 

 

InnerList

Gets an ArrayList instance representing the collection

 

 

instance. This can be used when implementing derived

Protected

 

classes to modify the collection.

 

 

Properties

List

Gets an IList instance representing the collection

 

 

 

instance. This can be used when implementing derived

 

 

classes to modify the collection.

 

 

 

 

OnClear

Performs additional custom processing before clearing the

 

 

contents of the collection. This can be used by derived

Protected

 

classes to perform any required actions before the

 

collection is cleared.

Methods

OnInsert

Performs additional custom processing before inserting an

 

 

 

element into a collection. A number of other protected

 

 

methods are provided, with a similar purpose.

 

 

 

132

CHAPTER 5 REUSABLE LIBRARIES

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