Architecture Net или что такое Microsoft.NET?




Интерфейсы коллекций

Теперь, достаточно подробно обсудив концепцию интерфейсов, мы можем обратить более пристальный взгляд на коллекции, в частности, на класс ArrayList (Список массивов), который мы активно использовали в программе Бюро путешествий Acme (Acme Travel Agency). Присмотревшись к определению класса ArrayList (Список массивов), можно увидеть, что он реализует четыре стандартных интерфейса.

// класс сборщика мусора ArrayList
_gс class ArrayList : public IList, ICollection,
lEnumerable, ICloneable

Первые три образуют несложную иерархическую структуру, показанную на рис. 5.1. При продвижении по структуре в интерфейсах появляются дополнительные методы, и, наконец, IList имеет наиболее полный их набор.

1.gif

Рис. 5.1. Иерархия интерфейсов для списков

Четвертый интерфейс из реализованных в ArrayList (Список массивов), ICloneable, является независимым от первых трех и предназначен для осуществления детального копирования объектов. Для знакомства с интерфейсами, обеспечивающими работу с коллекциями, рассмотрим программу StringList. Просмотрите главный метод Main программы StringList, а вспомогательные методы будут подробно рассматриваться по мере нашего знакомства с разными интерфейсами, предназначенными для работы с коллекциями.

//StringList.h
_gc class StringList
// класс сборщика мусора StringList
{
private: // частный
static ArrayList *pList; // статический
public:
static void Main() // статический Главный
{
// Инициализировать строки и показать начальное состояние
pList = new ArrayList(4);
ShowCount();
AddStringC'Amy") ; // Эми
AddStringC'Bob"); // Боб
AddString("Charlie"}; // Чарли
ShowEnum(pList);// счетчик
ShowCount ();
// Добавить еще две строки и снова показать состояние
AddString("David"); //Дэвид
AddString("Ellen"); // Эллен
ShowList(pList);// моделировать
foreach ShowCount (};
// Удалить две строки из списка и показать состояние
RemoveString("David"); // Дэвид RemoveAt(0);
ShowArray(pList);// запись индекса ShowCount();
// Попытка удалить две строки, которых нет в списке
RemoveString("Amy"); // Эми
RemoveAt(3);
}
private: // частный
static void ShowEnum(ArrayList *pArray) // статическая функция
{
lEnumerator *plter = pArray->GetEnumerator();
bool more = p!ter->MoveNext();
while (more)
{
String *pStr =
dynamic_cast<String *>((p!ter->Current));
Console::WriteLine(pStr);
more = p!ter->MoveNext();
}
}
static void ShowList(ArrayList *pArray) // статическая функция
{
lEnumerator *pEnum =
pArray->GetEnumerator() ;
while (pEnum->MoveNext() )
{
String *pStr =
dynamic_cast<String *>(pEnum->Current);
Console::WriteLine(pStr};
}
}
static void ShowArray(ArrayList *pArray) // статическая функция
{
for (int i = 0; i < pArray->Count; i++) f
Console::WriteLine(
"pArray->get_Item({0}) = {!}", _box (i) ,
pArray->get_Item(i)); } }
static void ShowCount() // статическая функция
{
Console::WriteLine(
"pList->Count = {0}", _box(pList->Count));
Console::WriteLine(
"pList->Capacity = {0}", _box(pList->Capacity));
// Вместимость
}
static void AddString (String *pStr) // статическая функция
{
if (pList->Contains(pStr)) // если содержит throw new Exception!
// новое Исключение
String::Format("list contains {0}", pStr)); // Формат: список содержит
pList->Add(pStr); // Добавить
}
static void RemoveString(String *pStr) // статическая функция
{
if (pList->Contains(pStr)) // если содержит
pList->Remove(pStr); // Удалить else
Console::WriteLine(
"List does not contain {0}", pStr); // Список
//не содержит
}
static void RemoveAt(int nlndex) // статическая функция
{
try // попытка
{
pList->RemoveAt(nlndex) ;
}
catch (ArgumentOutOfRangeException *)
{
Console::WriteLine(
"No element at index {0}", _box(nlndex));
// Нет элемента с таким индексом
}
}
};

Результат работы программы будет таким:

pList->Count = О
pList->Capacity = 4 // Вместимость
Amy // Эми
Bob // Боб
Charlie // Чарли
pList->Count = 3
pList->Capacity =4 // Вместимость
Amy // Эми
Bob // Боб
Charlie // Чарли
David // Дэвид
Ellen // Эллен
pList->Count = 5
pList->Capacity =8 // Вместимость
pArray->get_Item(0) = Bob // Боб
pArray->get_Item(1) = Charlie // Чарли
pArray->get_Item(2) = Ellen // Эллен
pList->Count = 3
pList->Capacity =8 // Вместимость
List does not contain Amy // Список не содержит Эми
No element at index 3 // Нет элемента с индексом 3

lEnumerableИ JEnumerator

Исходным для всех интерфейсов, предназначенных для работы с коллекциями, является интерфейс lEnumerable, имеющий один метод — GetEnumerator.

_gc _interface lEnumerable
// сборщик мусора - lEnumerable
{
lEnumerator* GetEnumerator();
};

GetEnumerator возвращает указатель на интерфейс lEnumerator, который используется для последовательного доступа к элементам коллекции. Этот интерфейс имеет свойство Current (Текущая запись) и методы MoveNext и Reset (Сброс).

_gc _interface lEnumerator
// сборщик мусора - lEnumerator
{
_property Object* get__Current () ;
bool MoveNext(); // логический (булев)
void Reset();
};

Сразу после инициализации нумератор указывает на позицию перед первым элементом коллекции и, следовательно, для получения доступа даже к первому ее элементу его следует продвинуть. Использование нумератора для последовательного доступа к элементам списка проиллюстрировано в методе ShowEnum.

static void ShowEnum(ArrayList *pArray) // статическая функция
{
lEnumerator *plter =
pArray->GetEnumerator();
bool more = piter->MoveNext(); // логическое значение while (more)
{
String *pStr =
dynamic_cast<String *>((p!ter->Current));
Console::WriteLine (pStr) ;
more = p!ter->MoveNext ();
}
}

Интерфейс ICollection

Интерфейс ICollection является производным от lEnumerable и в нем добавляются свойство Count (Количество) и метод СоруТо.

_gc _interface ICollection : public lEnumerable
// сборщик мусора - ICollection: lEnumerable
{
_property int get_Count();
_property bool get_IsSynchronized(); // логический
_property Object* get_SyncRoot();
void CopyTo(Array* array, int index); // массив, индекс
};

Кроме того, в данном интерфейсе появляются свойства, предназначенные для обеспечения синхронизации при использовании потоков. "Является ли безопасным использование потоков?" — вот один из часто задаваемых вопросов о любой библиотеке. Что касается среды .NET Framework, то ответ на этот вопрос короток и ясен — нет. Это не значит, что разработчики .NET Framework не задумывались о безопасности использования потоков. Наоборот, они реализовали множество механизмов, которые могут помочь вам при работе с потоками. Причина же, по которой использование потоков при работе с коллекциями не является безопасным автоматически, — в том, что обеспечение безопасности приводит к понижению производительности, а если ее обеспечить автоматически, то и при работе в однопотоковом режиме производительность окажется заниженной. Если же вам необходимо обеспечить безопасность при работе с потоками, вы можете использовать свойства интерфейса, предназначенные для синхронизации. Более подробно механизмы синхронизации потоков в .NET Framework будут рассмотрены в главе 8 "Классы каркаса .NET Framework".
Программа StringList иллюстрирует использование свойства Capacity (Объем) класса ArrayList (Список массивов), а также свойства Count (Количество), унаследованного классом ArrayList (Список массивов) от интерфейса ICollection.

static void ShowCount() // статическая функция
{
Console::WriteLine(
"pList->Count = {0}", _box(pList->Count)); // Счет
Console::WriteLine(
"pList->Capacity = {0}", _box(pList->Capacity));
// Вместимость
}

Интерфейс IList

Интерфейс IList является производным от интерфейса iCollection и в нем введены методы для добавления элемента в список, удаления его из списка и т.д.

_gc _interface IList : public ICollection
// сборщик мусора - IList: ICollection
{
_property bool get_IsFixedSize(); // логический
_property bool get_IsReadOnly(); // логический
_property Object* get_Item(int index); // индекс
_property void set_Item(int index, Object*); // индекс,
// Объект *
int Add(0bject* value); // Добавить значение
void Clear();
bool Contains(Object* value); // Содержит ли значение
int IndexOf(Object* value); // значение
void Insert(int index, Object* value); // Вставка (int индекс,
// Object* значение);
void Remove(Object* value); // Удалить значение
void RemoveAt(int index); // индекс };

В программе stringList продемонстрировано использование индексатора get_Item и методов Contains (Содержит), Add (Добавить), Remove (Удалить) и RemoveAt.

static void ShowArray(ArrayList *pArray)
{
for (int i = 0; i < pArray->Count; i++)
{
Console::WriteLine(
"pArray->get_Item({0}) = {!}", _box (i) ,
pArray->get_Item(i));
}
}
static void AddString(String *pStr)
{
if (pList->Contains(pStr))
// если содержит throw new Exception(
// новое Исключение
String::Format("list contains {0}", pStr));
// Формат:: ("список содержит")
pList->Add(pStr); // Добавить
}
i static void RemoveString(String *pStr)
{
if (pList->Contains(pStr)) // если содержит
pList->Remove(pStr); // Удалить
else
Console::WriteLine(
"List does not contain {0}", pStr); // Список
// не содержит
}
static void RemoveAtfint nlndex)
{
try // попытка
{
pList->RemoveAt(nIndex);
}
catch (ArgumentOutOfRangeException *)
{
Console::WriteLine(
"No element at index {0}", _box(nlndex)); // Нет элемента
//с индексом
}
}