Строго типизованные коллекции можно найти в библиотеках базовых классов .NET и это очень полезные программные конструкции. Однако эти пользовательские контейнеры мало помотают в решении проблем создания объектных образов. Даже если вы создадите пользовательскую коллекцию с именем IntCollection, предназначенную для работы только с типами данных System.Int32, вам придется создать объект некоторого типа для хранения самих данных (System.Array, System.Collections.ArrayList и т.п.).

public class IntCollection: IEnumerable {

 private ArrayList arInts = new ArrayList();

 public IntCollection() {}

 // Восстановление значения для вызывающей стороны.

 public int GetInt(int pos) { return (int)arInts[pos]; }

 // Операция создания объектного образа!

 public void AddInt(int i) { arInts.Add(i); }

 public void ClearInts() { arInts.Clear(); }

 public int Count { get { return arInts.Count; } }

 IEnumerator IEnumerable.GetEnumerator() { return arInts.GetEnumerator(); }

}

Вне зависимости от того, какой тип вы выберете для хранения целых чисел (System.Array, System.Collections.ArrayList и т.п.), вы не сможете избавиться от проблемы .NET 1.1, связанной с созданием объектных образов. Нетрудно догадаться, что здесь снова на помощь приходят обобщения. В следующем фрагменте программного кода тип System.Collections.Generic.List‹› используется для создания контейнера целых чисел, не имеющего проблем создания объектных образов и восстановлений значений при вставке и получении типов характеризуемых значений.

static void Main (string [] args) {

 // Баз создания объектного образа!

 List‹int› myInts = new List‹int›();

 myInts.Add.(5);

 // Без восстановления значения!

 int i = myInts[0];

}

Просто в качестве подтверждения рассмотрите следующий CIL-код для этого метода Main() (обратите внимание да отсутствие в нем каких бы то ни было блоков box и unbox).

.method private hidebysig static void Main(string[] args) cil managed {

 .entrypoint

 // Code size 24 (0x18)

 .maxstack 2

 .locals init ([0] class [mscorlib] System.Collections.Generic.List`1‹int32› myInts, [1] int32 i)

 IL_0000: nop

 IL_0001: newobj instance void class [mscorlib] System.Collections.Generic.List`1‹int32›::.ctor()

 IL_0006: stloc.0

 IL_0007: ldloc.0

 IL_0008: ldc.i4.5

 IL_0009: callvirt instance void class [mscorlib]System.Collections.Generic.List`1‹int32›::Add(!0)

 IL_000e: nop

 IL_000f: ldloc.0

 IL_0010: ldc.i4.0

 IL_0011: callvirt instance !0 class [mscorlib]System.Collections.Generic.List`1‹int32›::get_Item(int32)

 IL_0016: stloc.1

 IL_0017: ret

} // end of method Program::Main

Теперь, когда вы имеете лучшее представление о роли обобщений в .NET2.0, мы с вами готовы углубиться в детали. Для начала мы формально рассмотрим пространство имен System.Collections.Generic.

Исходный код. Проект CustomNonGenericCollection размещен в подкаталоге, соответствующем главе 10.

<p>Пространство имен System.Collections.Generic</p>

Обобщенные типы присутствуют во многих библиотеках базовых классов .NET 2.0, но пространство имен System.Collections.Generic буквально наполнено ими (что вполне соответствует его названию). Подобно своему "родственнику" без обобщений (System.Collections), пространство имен System.Collections. Generic содержит множество типов класса и интерфейса, что позволяет вкладывать элементы в самые разные контейнеры. Совсем не удивительно, что обобщенные интерфейсы имитируют соответствующие необобщенные типы из пространства имен System.Collections.

• ICollection‹T›

• IComparer‹T›

• IDictionary‹K, V›

• IEnumerable‹T›

• IEnumerator‹T›

• IList‹T›

Перейти на страницу:

Похожие книги