{

void Change (int x, int y);

}

public struct Point: IChange

{

public int x, y;

public void Change (int x, int y)

{

this. x = x; this. y = y;

}

Point (int x, int y)

{

Change(x, y);

}

}

Point p = new Point(5,3);// числа 5 и 3 записываются на стек

Object o = p;// произойдет упаковка в объект

((Point)o).Change(7,8); //так как тип - размерный, то произойдет распаковка на стеке и создатся временный объект, содержащий числа 7 и 8, который умрет и не внесет никаких изменений в объект p

Чтобы изменить значение p необходимо воспользоваться интерфейсом:

((IChange)o).Change(7,8);// здесь распаковки не будет

Интерфейсы сравнения (IComparable, IComparer)

Интерфейс IComparable, определенный в пространстве имен System, позволяет производить сортировку объектов, основываясь на специально определенном внутреннем ключе. Интерфейс IComparer, позволяет производить сортировку по нескольким ключам.

Формальное определение интерфейсов выглядит следующим образом:

interface IComparable

{

int CompareTo (Object o);

}

interface IComparer

{

int Compare (Object o1, Object o2);

}

В классе System. Array определен статический метод Sort(). С помощью этого метода можно упорядочить по возрастанию массив из элементов некоторых встроенных типов данных (например, таких как int и short).

Для того чтобы можно было стандартным способом производить сортировку пользовательских объектов, они должны реализовывать интерфейс IComparable. Поскольку этот интерфейс состоит из единственного метода CompareTo(), то надо всего лишь реализовать этот метод.

НЕ нашли? Не то? Что вы ищете?

public class Student: IComparable

{

int pareTo(Object o)

{

Student s = (Student) o;

return pareTo(s. name);

}

}

Student ss[] = new Student[5];

...

Array.Sort(ss); //все будет отсортировано по методу CompareTo

В отличие от интерфейса IComparable, IComparer обычно не реализуется напрямую внутри класса, объекты которого вы будете сортировать. Вместо этого этот интерфейс реализуется во вспомогательных классах, которых может быть любое количество – по одному вспомогательному классу на каждую переменную, по которой производится сортировка.

using System. Collections;

public class SortByName: IComparer

{

public SortByName () {}

int pare(Object o1, Object o2)

{

Student t1 = (Student) o1;

Student t2 = (Student) o2;

return pare(t1.name, t2.name);

}

}

Использовать этот вспомогательный класс очень просто: в System. Array предусмотрено множество вариантов перегруженного метода Sort(). Один из них и предназначен для приема объекта, реализующего IComparer:

Array. Sort(ss, new SortByName());

Интерфейсы IEnumerable и IEnumerator

Для перечисления элементов некоторого контейнера, конкретнее для использования конструкции foreach, необходимо чтобы класс реализовывал метод GetEnumerator(). Этот метод определяется в интерфейсе IEnumerable, который находится в пространстве имен System. Collections.

interface IEnumerable

{

IEnumerator GetEnumerator();

}

Если посмотреть, что делает GetEnumerator(), то выясниться, что он возвращает еще один интерфейс – IEnumerator. Этот интерфейс используется для обращения к членам внутреннего набора объектов. Он также находится в пространстве имен System. Collections и определяет следующие три метода:

public interface IEnumerator

{

bool MoveNext(); // Передвинуть внутренний указатель на одну позицию

object Current {get;} // Получить текущий элемент (свойство только для чтения)

void Reset(); // Установить внутренний указатель на начало

}

Создадим контейнер, реализующий интерфейсы IEnumerable, IEnumerator:

using System;

using System. Collections;

public class Students: IEnumerator, IEnumerable

{

int cur = -1;

int sz = 0;

Student[] ss;

Students(int n);

public bool MoveNext()

{

if ( cur<(sz-1) )

{

cur++;

return true;

}

else return false;

}

public void Reset()

{

cur = -1;

}

public object Current

{

get { return ss[cur];}

}

public IEnumerator GetEnumerator()

{

return (IEnumerator)this;

}

}

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

Коллекции

Классы коллекций расположены в пространстве имен System. Collections. Кроме того, в System. Collections определен набор стандартных интерфейсов. Многие из этих интерфейсов объединены в иерархии, в то время как некоторые существуют независимо от остальных.

Эти интерфейсы реализованы в большинстве коллекций.

Интерфейс

Назначение

ICollection

Определяет общие характеристики для класса-набора элементов

IComparer

Позволяет сравнивать два объекта

IDictionary

Позволяет представлять содержимое объекта в виде пар имя-значение

IDictionaryEnumerator

Используется для нумерации содержимого объекта, поддерживающего IDictionary

IEnumerable

Возращает интерфейс IEnumerator

IEnumerator

Обычно используется для поддержки конструкции foreach в отношении объектов

IHashCodeProvider

Возращает хэш-код для реализации типа с применением пользователем алгоритма хэширования

IList

Обеспечивает методы для добавления, удаления и индексирования в списке объектов

Приведем методы интерфейсов ICollection и IList. Действие большинства методов очевидно из названия.

interface ICollection

{

int Count {get;}

void CopyTo(Array a, int index);

}

interface IList: IEnumerable, ICollection

{

Object this[index]; //на чтение и запись

void Add(object obj);

void Clear();

bool Contains(object obj); // использует метод Equals

int IndexOf(obj); // возвращает -1 если нет такого объекта или индекс объекта. Использует метод Equals

void Insert(int ind, object obj);

void Remove(object obj);

void RemoveAt(object ind);

}

Рассмотрим наиболее распространенную коллекцию ArrayList. представляющую собой динамический массив:

class ArrayList: IList, ICollection, IEnumerable

{

void AddRange(ICollection с);

void Sort();

Sort(IComparer);

int BynarySearch(object obj); // объект должен реализовывать IComparable

ArrayList GetRange(int index, int count);

void SetRange(int index, ICollection c);

void RemoveRange(int index, int count);

void Reverse();

Object ToArray();

[] // индексатор

int Count // количество элементов

int Capacity // емкость (свойство на чтение)

void TrimToSize(); // делает Capacity равным Count

}

Приведем также интерфейсы коллекций Stack и Queue:

Queue: ICollection, IEnumerable

{

int Count; // количество элементов в очереди

void Clear();

bool Contains(object o); // содержится ли данный элемент в очереди

void CopyTo(Array a, int ind); // преобразовать очередь к массиву

void Enqueue(object o);

object Dequeue();

object Peck();

object [] ToArray(); // очередь преобразуется к массиву }

Stack: ICollection, IEnumerable

{

void Push(object o);

object Pop();

object Pick();

}

Ассоциативные массивы

Ассоциативные массивы предназначены для транения набора пар элементов вида (Ключ, Значение). К ним относятся классы HashTable и SortedList, каждый из которых реализует интерфейс IDictionary:

IDictionary: ICollection

{

ICollection Keys; // возвращает все ключи контейнеру, поддерживающему интерфейс ICollection

ICollection Value; // возвращает все значения контейнеру, поддерживающему интерфейс ICollection

Object this[Object Key] // по ключу возвращает значение

Add(Object key, Object value);

Clear();

bool Contains(object key); // проверяет, есть ли элемент с+ ключом key

void Remove(object key); // ищет элемент с ключом key и удаляет его

IDictionaryEnumerator GetEnumerator(); // возвращает указатель на элемент словаря

}

IDictionaryEnumerator: IEnumerator

{

Object key; // свойство на чтение

Object value; // свойство на чтение и на запись

DictionaryEntry Entry; // свойство Entry содержит свойства key и value

}

Класс HashTable представляет собой ассоциативный массив на базе хеш-таблицы. Он имеет следующий интерфейс:

class HashTable: ICollection, IDictionary

{

int Count;

Object this[Object Key]

ICollection Keys;

ICollection Values;

void Add(object key, object value);

void Remove(object key);

bool Contains(object key);

bool ContainsKey(object key);

bool ContainsValue(object value);

// конструкторы HashTable

HashTable();

HashTable(int n); // в конструкторе задается начальная емкость

HashTable(IDictionary d); // создание HashTable на основе контейнера, реализующего интерфейс IDictionary

}

Напомним, что поиск по хеш-таблице очень быстрый и не зависит от размера самой таблицы. Если таблица заполнена заполнена менее чем на 80%, то среднее время поиска < 3. Для корректной работы HashTable работала необходимо переопределить в классе ключей функцию GetHashCode(). Особенностью хеш-таблицы является то, что ключи в ней хранятся в неупорядоченном виде.

Следующая реализация интерфейса IDictionary – SortedList – представляет собой динамический массив пар и имеет следующие свойства и функции:

SortedList: ICollection, IDictionary

{

int Count;

ICollection Keys; // возвращает все ключи в виде контейнера, поддерживающего интерфейс ICollection

ICollection Value; // возвращает все значения в виде контейнера, поддерживающего интерфейс ICollection

Object this[Object Key]

int Capacity; // емкость

void SetByIndex(int index, object value);

value GetByIndex(int index);

key GetKey(int index);

IList GetKeyList(); // возвращает все ключи в виде контейнера, поддерживающего интерфейс IList

IList GetValueList(); // возвращает все значения в виде контейнера, поддерживающего интерфейс IList

int IndexOfKey(object key);

int IndexOfValue(object value);

void TrimToSize(); // приравнивает Count к Capacity

}

По объекту SortedList с помощью функции GetEnumerator можно пройти в отсортированном по ключам виде (в отличие от HashTable).

Приведем пример цикла по ассоциативному массиву с помощью итератора, в котором все значения увеличиваются на 1:

HashTable h = new HashTable();

h. Add("Иванов", 6);

h. Add("Петров", 5);

IDictionaryEnumerator ie = h. GetEnumerator();

while( ie. MoveNext() )

{

ie. Value = (int)ie. Value + 1;

}

Проектное задание

В проектное задание модуля 3 реализовать в каждом классе интерфейс ICloneable. Кроме этого, обеспечить сортировку всех студентов и всех преподавателей по нескольким критериям, реализовав в их классах соответствующие интерфейсы. Разработать также критерий сравнения, позволяющий сортировать в одном писке студентов и преподавателей.

Тест рубежного контроля

1. Сколько интерфейсов может реализовывать класс?

a. Не более одного

b. Множество

c. Множество, но в этом случае он не может наследоваться от другого класса

2. Если в классе MyClass метод интерфейса MyInt {void Menu();} реализован внешним и внутренним образом, то при вызове MyClass m = new MyClass(); ((MyInt)m).Menu();

a. Вызовется внешняя реализация интерфейса

b. Вызовется внутренняя реализация интерфейса

c. Произойдет ошибка компиляции

Литература

1. Д. Рихтер. CLR via C#. Программирование на платформе Microsoft .NET Framework 2.0 на языке C#. М., Питер, 2007, 636 с.

2. Т. Павловская. C#. Программирование на языке высокого уровня. М., Питер, 2007, 432 с.

Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4