Урок 34. Интерфейсы коллекции C#


В 34 части уроков по C# описывается использование коллекций в языке C#. Коллекция подобна массиву в том смысле, что она содержит группу объектов. Однако использование различных типов коллекций обеспечивает дополнительную функциональность.

Что такое коллекция?

Коллекция в C# - это группа связанных объектов, хранящихся в структуре. Существует много типов коллекций, определенных в .NET framework, каждый из которых предоставляет различную структуру объектов. К ним относятся коллекции для простых списков, очередей и стеков.

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

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

Упаковка и распаковка

Коллекции .NET 1.1 используются для хранения групп объектов. Это означает, что типы и структуры значений не могут содержаться в коллекции изначально. Тем не менее, можно удерживать значение или структуру в объекте, используя концепцию упаковки. Когда значение присваивается объекту, оно запаковывается и ведет себя как объект ссылочного типа. Позже объект может быть преобразован обратно в значение или распакован, приведя его к исходному типу данных.

В следующем примере показано значение, которое упаковывается и распаковывается.

int valueToBox = 123;
object boxed = valueToBox;                      // Упакован
int valueOutOfBox = (int)boxed;                 // Распакован
 
Console.WriteLine(valueOutOfBox);               // Вывод "123"
Примечание: при добавлении типов значений и структур в коллекцию упаковка происходит автоматически. При извлечении значения из коллекции оно должно быть распаковано с помощью оператора cast.

Тип коллекций

Существует три основных типа коллекций, предоставляемых платформой .NET framework:

  • Общего назначения. Коллекции общего назначения используются для предоставления стандартных структур данных, которые содержат любой тип объекта. К ним относятся массив динамического размера, стек и очередь. Они также включают справочники, которые содержат пары ключ-значение; каждая запись имеет как уникальный ключ, так и отдельный объект value.
  • Битовые коллекции. Битовые коллекции содержат группы двоичных цифр. Функциональные возможности этих коллекций специфичны для обработки битовых массивов, включая установку и сброс отдельных битов и выполнение побитовых логических операций.
  • Специализированный. Специализированные коллекции предназначены для оптимизированной обработки конкретных типов данных или структуры.
Каждый тип коллекции будет исследован в будущих статьях в учебнике C#. Кроме того, можно создать свои собственные типы коллекций, когда предоставляемые параметры не соответствуют вашим точным требованиям. Однако это выходит за рамки учебника для начинающих.

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

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

Каждый из ключевых интерфейсов описан ниже. Обратите внимание, что не все коллекции реализуют каждый интерфейс.

Интерфейс ICollection

Первый интерфейс - это ICollection . Каждая коллекция реализует этот интерфейс, его свойства и методы. Свойства и методы описаны в следующих разделах с примерами для ключевых элементов.

Примечание: все интерфейсы коллекции имеют префикс "I". Это общее соглашение об именовании.

ICollection.CopyTo

Метод CopyTo позволяет скопировать каждый элемент из коллекции в массив. Основной метод CopyTo принимает два параметра. Первый - это массив для заполнения. Второй - это целое число, представляющее индекс первого элемента в массиве для копирования. Каждый элемент из коллекции помещается в последующие индексы массива.

В приведенном ниже примере коллекция копируется в нулевой индекс массива, который является первым элементом. В этом примере демонстрируется использование CopyTo для ArrayList, обычно используемой коллекции, предоставляющей одномерную динамическую структуру массива. ArrayList находится в System.Collections пространстве имён, так что, чтобы выполнить пример, добавьте с using System.Collections; к исходному коду.

ArrayList names = new ArrayList();
 
// Add some names
names.Add("Andrew");
names.Add("Alex");
names.Add("Adrienne");
 
// Copy the collection into a new array of strings
string[] namesArray = new string[3];
names.CopyTo(namesArray, 0);
 
foreach(string name in namesArray)
{
    Console.WriteLine(name);
}
 
/* Вывод
 
Andrew
Alex
Adrienne
 
*/
Примечание: строки используются на протяжении всей этой статьи в примерах. Они используются только для удобства демонстрации и могут быть заменены любым типом объекта.

ICollection.Count

Свойство Count возвращает количество элементов, существующих в коллекции, в виде целого значения.

ArrayList names = new ArrayList();
 
// Add some names
names.Add("Andrew");
names.Add("Alex");
names.Add("Adrienne");
 
Console.WriteLine(names.Count);                 // Вывод "3"
ICollection.IsSynchronized

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

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

ArrayList names = new ArrayList();
 
Console.WriteLine(names.IsSynchronized);        // Вывод "False"
ICollection.SyncRoot

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

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

ArrayList names = new ArrayList();
 
// Add some names
names.Add("Andrew");
names.Add("Alex");
names.Add("Adrienne");
 
lock (names.SyncRoot)                           // Lock the collection
{
    foreach(string name in names)
    {
        Console.WriteLine(name);
    }
}                                               // Collection now unlocked
 
/* Вывод
 
Andrew
Alex
Adrienne
 
*/
Интерфейс IList

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

Члены интерфейса IList описаны ниже. Обратите внимание, что не все коллекции поддерживают каждое поведение. Если метод или свойство не поддерживается, вызывая его вызывает NotSupportedException . Интерфейс IList является производным от ICollection или наследует его. Это означает, что все коллекции, поддерживающие поведение IList, также реализуют ICollection.

IList.Add

Метод Add добавляет новый объект в коллекцию; объект для добавления передается в единственный параметр. Метод возвращает целочисленное значение, указывающее позицию индекса, в которую был вставлен новый объект. Помните, что индекс начинается с нуля, поэтому первая запись находится в нулевой позиции.

ArrayList names = new ArrayList();
 
// Add some names
names.Add("Andrew");
names.Add("Alex");
int position = names.Add("Adrienne");
 
Console.WriteLine(position);                    // Вывод "2"
IList.Remove

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

ArrayList names = new ArrayList();
 
// Add some names
names.Add("Andrew");
names.Add("Alex");
names.Add("Adrienne");
names.Remove("Andrew");
 
Console.WriteLine(names.Count);                 // Вывод "2"
IList.Insert

Метод Insert аналогичен методу Add, так как он позволяет добавлять новые элементы в коллекцию. При вставке указывается индекс нового элемента. Объект вставляется в указанный индекс, а существующие объекты перемещаются в более высокий индекс, чтобы освободить место. Если указанный номер индекса слишком велик, создается исключение ArgumentOutOfRangeException.

ArrayList names = new ArrayList();
 
// Add some names
names.Add("Andrew");
names.Add("Alex");
names.Insert(0, "Adrienne");                    // Insert at start of collection
 
foreach(string name in names)
{
    Console.WriteLine(name);
}
 
/* Вывод
 
Adrienne
Andrew
Alex
 
*/
RemoveAt

Метод RemoveAt удаляет элемент из коллекции, используя номер индекса для идентификации объекта для удаления. Все элементы в коллекции с более высоким индексом перемещаются, чтобы гарантировать, что индексы остаются непрерывными.

ArrayList names = new ArrayList();
 
// Add some names
names.Add("Andrew");
names.Add("Alex");
names.Add("Adrienne");
names.RemoveAt(1);                              // Remove the second item
 
foreach(string name in names)
{
    Console.WriteLine(name);
}
 
/* Вывод
 
Andrew
Adrienne
 
*/
IList.Clear

Метод Clear является последним методом IList, используемым для изменения содержимого коллекции. Он удаляет все элементы из коллекции.

ArrayList names = new ArrayList();
 
// Add some names
names.Add("Andrew");
names.Add("Alex");
names.Add("Adrienne");
names.Clear();
 
Console.WriteLine(names.Count);                 // Вывод "0"
IList.Contains

Иногда необходимо определить, существует ли объект в коллекции. Метод Contains может быть использован для этой цели путем передачи объекта для поиска в качестве единственного параметра. Метод возвращает true, если элемент присутствует, и false в противном случае.

ArrayList names = new ArrayList();
 
// Add some names
names.Add("Andrew");
names.Add("Alex");
names.Add("Adrienne");
 
Console.WriteLine(names.Contains("Alex"));      // Вывод "True"
Console.WriteLine(names.Contains("Albert"));    // Вывод "False"
IList.IndexOf

Конечным методом интерфейса IList является IndexOf . Этот метод аналогичен методу Contains, так как он используется для определения наличия объекта в коллекции. Если объект существует, то возвращается его порядковый номер. Если объект не существует, возвращаемое значение равно -1.

ArrayList names = new ArrayList();
 
// Add some names
names.Add("Andrew");
names.Add("Alex");
names.Add("Adrienne");
 
Console.WriteLine(names.IndexOf("Alex"));       // Вывод "1"
Console.WriteLine(names.IndexOf("Brian"));      // Вывод "-1"
IList.IsFixedSize Хотя большинство коллекций предоставляют динамическую группу элементов, можно иметь коллекции фиксированного размера. Коллекция фиксированного размера может быть изменена, но новые элементы не могут быть добавлены, а существующие элементы не могут быть удалены. Если какая-либо операция предпринята, создается исключение NotSupportedException. Чтобы проверить, является ли коллекция фиксированной по размеру, прочитайте свойство Boolean IsFixedSize.

ArrayList names = new ArrayList();
 
Console.WriteLine(names.IsFixedSize);           // Вывод "False"
IList.IsReadOnly

Еще одним шагом вперед по сравнению с коллекцией фиксированного размера является коллекция только для чтения. Такой список никоим образом не может быть изменен. Чтобы проверить, доступна ли коллекция только для чтения, прочитайте свойство IsReadOnly.

ArrayList names = new ArrayList();
 
Console.WriteLine(names.IsReadOnly);            // Вывод "False"
Примечание: коллекции фиксированного размера и только для чтения обычно являются оболочками для существующих коллекций, которые ограничивают доступ к записи. Если базовая коллекция изменена, ограниченная версия отражает изменения без выброса исключения.

IList.Item

Свойство Item предоставляет прямой доступ к любому объекту в коллекции с использованием номера индекса. Для указания номера индекса используются квадратные скобки, как и в массивах. В следующем примере создается и заполняется ArrayList с помощью метода Add. Значение одного из элементов коллекции затем считывается, изменяется и снова считывается номер индекса.

ArrayList names = new ArrayList();
 
// Добавляем имена
names.Add("Andrew");
names.Add("Alex");
names.Add("Adrienne");
 
Console.WriteLine(names[1]);
names[1] = "Alan";
Console.WriteLine(names[1]);
 
/* Вывод
 
Alex
Alan
 
*/
Примечание: это свойство называется индексатором для коллекции IList.

IDictionary Interface

Dictionary - это коллекция, содержащая связанные пары ключ-значение. Каждая запись в коллекции состоит из двух объектов. Первый, называемый ключом, является уникальным объектом, который идентифицирует запись в коллекции. Второй - это объект value. Это значение не обязательно должно быть уникальным.

Интерфейс IDictionary реализован во всех коллекциях справочников. Как и в случае с IList, IDictionary наследует ICollection, поэтому также поддерживает все поведение ICollection.

IDictionary.Add

Метод Add в IDictionary аналогичен методу IList.Метод add. Он используется для добавления нового элемента в словарь. Поскольку словари идентифицируются указанным ключом, а не номером индекса, значение не возвращается.

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

Hashtable users = new Hashtable();
 
// Add some users
users.Add("andyb", "Andrew Brown");
users.Add("alexg", "Alex Green");
users.Add("adrienneb", "Adrienne Black");
 
Console.WriteLine(users.Count);                 // Вывод "3"
Remove

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

Hashtable users = new Hashtable();
 
// Add some users
users.Add("andyb", "Andrew Brown");
users.Add("alexg", "Alex Green");
users.Add("adrienneb", "Adrienne Black");
users.Remove("andyb");
 
Console.WriteLine(users.Count);                 // Вывод "2"
IDictionary.Clear

Метод Clear удаляет все элементы из справочника. Этот метод аналогичен методу Clear интерфейса IList.

IDictionary.Contains

Метод Contains предоставляет аналогичные функциональные возможности для IList.Содержит. Он возвращает логическое значение, указывающее, существует ли определенный ключ в словаре.

Hashtable users = new Hashtable();
 
// Добавляем пользователей
users.Add("andyb", "Andrew Brown");
users.Add("alexg", "Alex Green");
users.Add("adrienneb", "Adrienne Black");
 
Console.WriteLine(users.Contains("alexg"));       // Вывод "True"
Console.WriteLine(users.Contains("Alex Green"));  // Вывод "False"

IDictionary.IsFixedSize и IDictionary.IsReadOnly
В описании свойств интерфейса IList было объяснено, что коллекции могут иметь фиксированный размер или быть доступны только для чтения. Это верно для коллекций словарей, поэтому IDictionary предоставляет свойства IsFixedSize и IsReadOnly; оба возвращают логическое значение.

IDictionary.Item

Интерфейс IDictionary определяет свойство Item в качестве индексатора для классов словарей. Это позволяет идентифицировать отдельные элементы коллекции с помощью индекса, заключенного в квадратные скобки. В случае словарей используется ключевой объект, а не номер индекса.

Hashtable users = new Hashtable();
 
// Add some users
users.Add("andyb", "Andrew Brown");
users.Add("alexg", "Alex Green");
users.Add("adrienneb", "Adrienne Black");
 
Console.WriteLine(users["alexg"]);              // Вывод "Alex Green"
IDictionary.Keys и IDictionary.Values

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

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

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

Hashtable users = new Hashtable();
 
// Add пользователей
users.Add("andyb", "Andrew Brown");
users.Add("alexg", "Alex Green");
users.Add("adrienneb", "Adrienne Black");
 
// Extract the keys and values
ICollection keys = users.Keys;
ICollection values = users.Values;
 
// Loop through each key and value
foreach(object key in keys)
{
    Console.WriteLine(key);
} 
 
foreach(object value in values)
{
    Console.WriteLine(value);
}
 
/* Вывод
 
adrienneb
alexg
andyb
Adrienne Black
Alex Green
Andrew Brown
 
*/
Enumerators

В приведенных выше примерах команда foreach использовалась для циклического перебора элементов в коллекции. Это возможно, потому что интерфейс ICollection поддерживает интерфейс IEnumerable.
Автор этого материала - я - Пахолков Юрий. Я оказываю услуги по написанию программ на языках Java, C++, C# (а также консультирую по ним) и созданию сайтов. Работаю с сайтами на CMS OpenCart, WordPress, ModX и самописными. Кроме этого, работаю напрямую с JavaScript, PHP, CSS, HTML - то есть могу доработать ваш сайт или помочь с веб-программированием. Пишите сюда.

тегистатьи IT, уроки по си шарп, си шарп, коллекции, интерфейс




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




Урок 19. Оператор if...else JavaScript
Штукатурные работы
Пошаговое руководство по верстке на опенкарт. Глава первая: введение и главная страница