Обобщенные системные коллекции

Похоже, что наиболее естественное применение обобщений в С# и CLR относится к типам коллекций. Возможно, это потому, что за счет применения для хранения типов значений обобщенных контейнеров можно получить огромный прирост эффективности по сравнению с типами коллекций из пространства имен System.Collections.

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

Настоятельно рекомендуется изучить описание пространства имен System.Collections.Generic в документации по .NET Framework. Там вы найдете все классы обобщенных коллекций, которые стали доступными в .NET Framework. В это пространство имен входят Dictionary, LinkedList, List, Queue, SortedDictionary, SortedList, HashSet и Stack.

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

Хотя набор контейнеров внутри пространства имен System.Collections.Generic может показаться недостаточным для существующих потребностей, всегда есть возможность создавать собственные коллекции, особенно на базе расширяемых типов из пространства System.Collections.ObjectModel.

При создании собственных типов коллекций часто будет возникать потребность в сравнении объектов, хранящихся в коллекции. При кодировании на С# кажется естественным применять для выполнения сравнений встроенные операции равенства и неравенства.

Однако лучше воздерживаться от этого, поскольку поддержка таких операций классами и структурами, хоть и возможна, но не является частью спецификации CLS.

Некоторые языки имеют слишком медленную поддержку этих операций. Поэтому контейнер должен быть специально подготовлен к тем случаям, когда содержащиеся в нем типы не поддерживают операций сравнения. Это одна из причин существования таких интерфейсов, как IComparer и IComparable.

При создании экземпляра типа SortedList внутри System.Collections имеется возможность предоставить экземпляр объекта, поддерживающего IComparer. Тип SortedList будет использовать этот объект, когда возникнет необходимость в сравнении двух экземпляров ключей, содержащихся в нем. Если не предоставить объекта, поддерживающего IComparer, то SortedList для проведения сравнения будет искать реализации интерфейса IComparable в содержащихся объектах ключей.

Естественно, если содержащиеся в коллекции объекты ключей не поддерживают IComparable, понадобится предоставить явный компаратор. Перегруженные версии конструктора, принимающие тип IComparer, предназначены специально для этого.

Обобщенная версия сортированного списка SortedList следует тому же шаблону в отношении сортировки. При создании экземпляра SortedList есть возможность предоставить объект, реализующий интерфейс IComparer, чтобы он сравнивал два ключа.

Если этого не сделать, то SortedList по умолчанию воспользуется так называемым обобщенным компаратором. Обобщенный компаратор — это просто объект, унаследованный от абстрактного класса Comparer, который может быть получен через статическое свойство Comparer.Default.

Исходя из необобщенного варианта SortedList, может показаться, что если создатель объекта SortedList не предусмотрел компаратор, он можно просто поискать реализацию IComparable в типе содержащегося ключа. Такой подход привел бы к проблемам, поскольку тип содержащегося ключа может поддерживать как IComparable, так и необобщенный IComparable.

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

Рассмотрим пример, иллюстрирующий сказанное выше:

1
2
3
4
5
6
7
8
9
10
11
12
13
using System;
using System.Collections.Generic;
public class EntryPoint
{
static void Main()  {
SortedList<int, string> listl = new SortedList<int, string>();
SortedList<int, string> list2 =
new SortedList<int, string> ( Comparer<int>.Default );
listl.Add ( 1, "one" ) ;
listl.Add( 2, "two" ) ;
list2.Add( 3, "three" ) ;
list2.Add( 4, "four" ) ;
}

Здесь объявлены два экземпляра SortedList. В первом экземпляре использовался конструктор без параметров, а во втором явно предоставлен компаратор для целых чисел. В обоих случаях получается один и тот же результат, потому что в конструкторе list2 был передан обобщенный компаратор по умолчанию.

Это сделано главным образом для того, чтобы можно было увидеть синтаксис, применяемый для передачи обобщенного компаратора по умолчанию. Столь же легко можно предоставить любой другой тип в списке параметров-типов для Comparer, при условии, что он поддерживает либо IComparable, либо IComparable.

Вы можете следить за любыми ответами на эту запись через RSS 2.0 ленту. Вы можете оставить ответ, или trackback с вашего собственного сайта.

Оставьте отзыв

XHTML: Вы можете использовать следующие теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

 
Rambler's Top100