Была ли эта страница полезной?
Ваш отзыв об этом контенте важен для нас. Расскажите нам о том, что вы думаете.
Дополнительный отзыв?
1500 символов осталось
Экспорт (0) Печать
Развернуть все
Эта статья переведена вручную. Наведите указатель мыши на предложения статьи, чтобы просмотреть исходный текст. Дополнительные сведения.
Перевод
Текст оригинала

Коллекции (C# и Visual Basic)

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

Массивы удобнее всего использовать для создания и работы с фиксированным числом строго типизированных объектов. Сведения о массивах см. в разделах Массивы в Visual Basic или Массивы (Руководство по программированию на C#).

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

Коллекция является классом, поэтому необходимо объявить новую коллекцию перед добавлением в неё элементов.

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

Примечание Примечание

Для примеров в данном разделе включите операторы Imports (Visual Basic) или директивы using (C#) для пространств имен System.Collections.Generic и System.Linq.

Содержание раздела

В примерах этого раздела используется универсальный класс List, который позволяет работать со строго типизированными списками объектов.

В следующем примере создается список строк, а затем просматриваются строки с помощью оператора For Each…Next (Visual Basic) или foreach (C#).

// Create a list of strings. 
var salmons = new List<string>();
salmons.Add("chinook");
salmons.Add("coho");
salmons.Add("pink");
salmons.Add("sockeye");

// Iterate through the list. 
foreach (var salmon in salmons)
{
    Console.Write(salmon + " ");
}
// Output: chinook coho pink sockeye

Если содержимое коллекции известно заранее, можно использовать инициализатор коллекции для инициализации коллекции. Дополнительные сведения см. в разделе Инициализаторы коллекций (Visual Basic) или Инициализаторы объектов и коллекций (Руководство по программированию в C#).

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

// Create a list of strings by using a 
// collection initializer. 
var salmons = new List<string> { "chinook", "coho", "pink", "sockeye" };

// Iterate through the list. 
foreach (var salmon in salmons)
{
    Console.Write(salmon + " ");
}
// Output: chinook coho pink sockeye

Для выполнения итерации по коллекции можно использовать оператор For…Next (Visual Basic) или for (C#) вместо оператора For Each. Это выполняется путем доступа к элементам коллекции по позиции индекса. Индекс элементов начинается с 0 и заканчивается на числе, равном количеству элементов за вычетом 1.

В следующем примере выполняется перебор элементов коллекции с помощью For…Next вместо For Each.

// Create a list of strings by using a 
// collection initializer. 
var salmons = new List<string> { "chinook", "coho", "pink", "sockeye" };

for (var index = 0; index < salmons.Count; index++)
{
    Console.Write(salmons[index] + " ");
}
// Output: chinook coho pink sockeye

Следующий пример удаляет элемент из коллекции путем указания объекта для удаления.

// Create a list of strings by using a 
// collection initializer. 
var salmons = new List<string> { "chinook", "coho", "pink", "sockeye" };

// Remove an element from the list by specifying 
// the object.
salmons.Remove("coho");

// Iterate through the list. 
foreach (var salmon in salmons)
{
    Console.Write(salmon + " ");
}
// Output: chinook pink sockeye

В следующем примере удаляются элементы из универсального списка. Вместо оператора For Each, используется оператор For…Next (Visual Basic) или for (C#), проходящий в порядке убывания. Это так, потому что в результате работы метода RemoveAt элементы, следующие за удаленным элементом, имеют меньшее значение индекса.

var numbers = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

// Remove odd numbers. 
for (var index = numbers.Count - 1; index >= 0; index--)
{
    if (numbers[index] % 2 == 1)
    {
        // Remove the element by specifying 
        // the zero-based index in the list.
        numbers.RemoveAt(index);
    }
}

// Iterate through the list. 
// A lambda expression is placed in the ForEach method 
// of the List(T) object.
numbers.ForEach(
    number => Console.Write(number + " "));
// Output: 0 2 4 6 8

Для типа элементов в List можно также определить собственный класс. В следующем примере класс Galaxy, который используется объектом List, определен в коде.

private void IterateThroughList()
{
    var theGalaxies = new List<Galaxy>
        {
            new Galaxy() { Name="Tadpole", MegaLightYears=400},
            new Galaxy() { Name="Pinwheel", MegaLightYears=25},
            new Galaxy() { Name="Milky Way", MegaLightYears=0},
            new Galaxy() { Name="Andromeda", MegaLightYears=3}
        };

    foreach (Galaxy theGalaxy in theGalaxies)
    {
        Console.WriteLine(theGalaxy.Name + "  " + theGalaxy.MegaLightYears);
    }

    // Output: 
    //  Tadpole  400 
    //  Pinwheel  25 
    //  Milky Way  0 
    //  Andromeda  3
}

public class Galaxy
{
    public string Name { get; set; }
    public int MegaLightYears { get; set; }
}

Многие типовые коллекции предоставляются платформой .NET Framework. Каждый тип коллекции предназначен для определенной цели.

Следующие группы классов коллекций описаны в этом разделе:

  • Классы System.Collections.Generic

  • Классы System.Collections.Concurrent

  • Классы System.Collections

  • Класс Collection в Visual Basic

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

В следующей таблице перечислены некоторые из часто используемых классов пространства имен System.Collections.Generic:

Класс

Описание

Dictionary

Предоставляет коллекцию пар ключ/значение, которые упорядочены по ключу.

List

Представляет список объектов, доступных по индексу. Предоставляет методы для поиска по списку, выполнения сортировки и изменения списка.

Queue

Предоставляет коллекцию объектов, которая обслуживается по принципу "первым пришел — первым вышел" (FIFO).

SortedList

Представляет коллекцию пар ключ/значение, упорядоченных по ключу на основе реализации IComparer.

Stack

Представляет коллекцию объектов, которая обслуживается по принципу "последним пришел — первым вышел" (LIFO).

Дополнительные сведения см. в описаниях Часто используемые типы коллекций, Выбор класса коллекции и System.Collections.Generic.

В .NET Framework 4 коллекции пространства имен System.Collections.Concurrent предоставляют эффективные потокобезопасные операции для доступа к элементам коллекции из нескольких потоков.

Классы пространства имен System.Collections.Concurrent следует использовать вместо соответствующих типов пространств имен System.Collections.Generic и System.Collections, если несколько потоков параллельно обращаются к такой коллекции. Дополнительные сведения см. в разделах Потокобезопасные коллекции и System.Collections.Concurrent.

Некоторые из классов, входящих в пространство имен System.Collections.Concurrent — это BlockingCollection, ConcurrentDictionary, ConcurrentQueue и ConcurrentStack.

Классы в пространстве имен System.Collections не хранят элементы в виде конкретно типизированных объектов, а хранят их как объекты типа Object.

Везде, где это возможно, следует использовать универсальные коллекции пространства имен System.Collections.Generic или пространства имен System.Collections.Concurrent вместо устаревших типов пространства имен System.Collections.

В следующей таблице перечислены некоторые из часто используемых классов в пространстве имен System.Collections:

Класс

Описание

ArrayList

Представляет массив объектов, размер которого динамически увеличивается по мере необходимости.

Hashtable

Предоставляет коллекцию пар ключ/значение, которые упорядочены по хэш-коду ключа.

Queue

Предоставляет коллекцию объектов, которая обслуживается по принципу "первым пришел — первым вышел" (FIFO).

Stack

Представляет коллекцию объектов, которая обслуживается по принципу "последним пришел — первым вышел" (LIFO).

Пространство имен System.Collections.Specialized предоставляет специализированные строго типизированные классы коллекций, такие как коллекции строк, связанные списки и гибридные словари.

Можно использовать класс Collection Visual Basic для доступа к элементу коллекции по числовому индексу или ключу String. Можно добавлять элементы в объект коллекции с указанием или без указания ключа. Если добавить объект без ключа, необходимо использовать его числовой индекс для доступа к нему.

Класс Collection Visual Basic хранит все свои элементы как тип Object, поэтому можно добавить элемент любого типа данных. Нет никакой защиты от добавления неподходящих типов данных.

При использовании класса Collection Visual Basic первый элемент в коллекции имеет индекс 1. Это отличается от классов коллекций платформы .NET Framework, для которых начальный индекс равен 0.

Везде, где это возможно, следует использовать универсальные коллекции в пространстве имен System.Collections.Generic или пространстве имен System.Collections.Concurrent вместо класса Collection Visual Basic.

Дополнительные сведения см. в разделе Collection.

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

В следующем примере создается коллекция Dictionary и последовательно перебирается словарь с помощью оператора For Each.

private void IterateThruDictionary()
{
    Dictionary<string, Element> elements = BuildDictionary();

    foreach (KeyValuePair<string, Element> kvp in elements)
    {
        Element theElement = kvp.Value;

        Console.WriteLine("key: " + kvp.Key);
        Console.WriteLine("values: " + theElement.Symbol + " " +
            theElement.Name + " " + theElement.AtomicNumber);
    }
}

private Dictionary<string, Element> BuildDictionary()
{
    var elements = new Dictionary<string, Element>();

    AddToDictionary(elements, "K", "Potassium", 19);
    AddToDictionary(elements, "Ca", "Calcium", 20);
    AddToDictionary(elements, "Sc", "Scandium", 21);
    AddToDictionary(elements, "Ti", "Titanium", 22);

    return elements;
}

private void AddToDictionary(Dictionary<string, Element> elements,
    string symbol, string name, int atomicNumber)
{
    Element theElement = new Element();

    theElement.Symbol = symbol;
    theElement.Name = name;
    theElement.AtomicNumber = atomicNumber;

    elements.Add(key: theElement.Symbol, value: theElement);
}

public class Element
{
    public string Symbol { get; set; }
    public string Name { get; set; }
    public int AtomicNumber { get; set; }
}

Чтобы вместо этого использовать инициализатор коллекции для сборки коллекции Dictionary, можно заменить методы BuildDictionary и AddToDictionary следующим методом.

private Dictionary<string, Element> BuildDictionary2()
{
    return new Dictionary<string, Element>
    {
        {"K",
            new Element() { Symbol="K", Name="Potassium", AtomicNumber=19}},
        {"Ca",
            new Element() { Symbol="Ca", Name="Calcium", AtomicNumber=20}},
        {"Sc",
            new Element() { Symbol="Sc", Name="Scandium", AtomicNumber=21}},
        {"Ti",
            new Element() { Symbol="Ti", Name="Titanium", AtomicNumber=22}}
    };
}

В следующем примере используется метод ContainsKey и свойство ItemDictionary, чтобы быстро найти элемент по ключу. Свойство Item позволяет получить доступ к элементу в коллекции elements с помощью кода elements(symbol) в Visual Basic или elements[symbol] в C#.

private void FindInDictionary(string symbol)
{
    Dictionary<string, Element> elements = BuildDictionary();

    if (elements.ContainsKey(symbol) == false)
    {
        Console.WriteLine(symbol + " not found");
    }
    else
    {
        Element theElement = elements[symbol];
        Console.WriteLine("found: " + theElement.Name);
    }
}

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

private void FindInDictionary2(string symbol)
{
    Dictionary<string, Element> elements = BuildDictionary();

    Element theElement = null;
    if (elements.TryGetValue(symbol, out theElement) == false)
        Console.WriteLine(symbol + " not found");
    else
        Console.WriteLine("found: " + theElement.Name);
}

Для доступа к коллекции может использоваться язык интегрированных запросов (LINQ). Запрос LINQ обеспечивает возможности фильтрации, упорядочения и группировки. Дополнительные сведения см. в разделе Приступая к работе с LINQ в Visual Basic или Приступая к работе с LINQ в C#.

В следующем примере выполняется запрос LINQ к универсальному List. Запрос LINQ возвращает другую коллекцию, содержащую результаты.

private void ShowLINQ()
{
    List<Element> elements = BuildList();

    // LINQ Query. 
    var subset = from theElement in elements
                 where theElement.AtomicNumber < 22
                 orderby theElement.Name
                 select theElement;

    foreach (Element theElement in subset)
    {
        Console.WriteLine(theElement.Name + " " + theElement.AtomicNumber);
    }

    // Output: 
    //  Calcium 20 
    //  Potassium 19 
    //  Scandium 21
}

private List<Element> BuildList()
{
    return new List<Element>
    {
        { new Element() { Symbol="K", Name="Potassium", AtomicNumber=19}},
        { new Element() { Symbol="Ca", Name="Calcium", AtomicNumber=20}},
        { new Element() { Symbol="Sc", Name="Scandium", AtomicNumber=21}},
        { new Element() { Symbol="Ti", Name="Titanium", AtomicNumber=22}}
    };
}

public class Element
{
    public string Symbol { get; set; }
    public string Name { get; set; }
    public int AtomicNumber { get; set; }
}

Следующий пример демонстрирует процедуру сортировки коллекции. В примере сортируются экземпляры класса Car, которые хранятся в List. Класс Car реализует интерфейс IComparable, который требует, чтобы метод CompareTo был реализован.

Каждый вызов метода CompareTo делает одно сравнение, используемое для сортировки. Написанный пользователем код в методе CompareTo возвращает значение для каждого сравнения текущего объекта с другим объектом. Возвращаемое значение меньше нуля, если текущий объект меньше другого объекта, больше нуля, если текущий объект больше другого объекта, а также равняется нулю, если объекты равны. Это позволяет определить в коде условия для отношения "больше", "меньше" и "равно".

В методе ListCars оператор cars.Sort() сортирует список. Этот вызов метода SortList приводит к тому, что метод CompareTo вызывается автоматически для объектов Car в List.

private void ListCars()
{
    var cars = new List<Car>
    {
        { new Car() { Name = "car1", Color = "blue", Speed = 20}},
        { new Car() { Name = "car2", Color = "red", Speed = 50}},
        { new Car() { Name = "car3", Color = "green", Speed = 10}},
        { new Car() { Name = "car4", Color = "blue", Speed = 50}},
        { new Car() { Name = "car5", Color = "blue", Speed = 30}},
        { new Car() { Name = "car6", Color = "red", Speed = 60}},
        { new Car() { Name = "car7", Color = "green", Speed = 50}}
    };

    // Sort the cars by color alphabetically, and then by speed 
    // in descending order.
    cars.Sort();

    // View all of the cars. 
    foreach (Car thisCar in cars)
    {
        Console.Write(thisCar.Color.PadRight(5) + " ");
        Console.Write(thisCar.Speed.ToString() + " ");
        Console.Write(thisCar.Name);
        Console.WriteLine();
    }

    // Output: 
    //  blue  50 car4 
    //  blue  30 car5 
    //  blue  20 car1 
    //  green 50 car7 
    //  green 10 car3 
    //  red   60 car6 
    //  red   50 car2
}

public class Car : IComparable<Car>
{
    public string Name { get; set; }
    public int Speed { get; set; }
    public string Color { get; set; }

    public int CompareTo(Car other)
    {
        // A call to this method makes a single comparison that is 
        // used for sorting. 

        // Determine the relative order of the objects being compared. 
        // Sort by color alphabetically, and then by speed in 
        // descending order. 

        // Compare the colors. 
        int compare;
        compare = String.Compare(this.Color, other.Color, true);

        // If the colors are the same, compare the speeds. 
        if (compare == 0)
        {
            compare = this.Speed.CompareTo(other.Speed);

            // Use descending order for speed.
            compare = -compare;
        }

        return compare;
    }
}

Можно определить коллекцию путем реализации интерфейса IEnumerable или IEnumerable. Дополнительные сведения см. в разделах Перечисление коллекции и Практическое руководство. Доступ к классу коллекции с помощью оператора foreach (Руководство по программированию в C#).

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

В следующем примере определяется пользовательская коллекция с именем AllColors. Этот класс реализует интерфейс IEnumerable, который требует, чтобы метод GetEnumerator был реализован.

Метод GetEnumerator возвращает экземпляр класса ColorEnumerator. ColorEnumerator реализует интерфейс IEnumerator, который требует, чтобы были реализованы свойство Current, метод MoveNext и метод Reset.

private void ListColors()
{
    var colors = new AllColors();

    foreach (Color theColor in colors)
    {
        Console.Write(theColor.Name + " ");
    }
    Console.WriteLine();
    // Output: red blue green
}


// Collection class. 
public class AllColors : System.Collections.IEnumerable
{
    Color[] _colors =
    {
        new Color() { Name = "red" },
        new Color() { Name = "blue" },
        new Color() { Name = "green" }
    };

    public System.Collections.IEnumerator GetEnumerator()
    {
        return new ColorEnumerator(_colors);

        // Instead of creating a custom enumerator, you could 
        // use the GetEnumerator of the array. 
        //return _colors.GetEnumerator();
    }

    // Custom enumerator. 
    private class ColorEnumerator : System.Collections.IEnumerator
    {
        private Color[] _colors;
        private int _position = -1;

        public ColorEnumerator(Color[] colors)
        {
            _colors = colors;
        }

        object System.Collections.IEnumerator.Current
        {
            get
            {
                return _colors[_position];
            }
        }

        bool System.Collections.IEnumerator.MoveNext()
        {
            _position++;
            return (_position < _colors.Length);
        }

        void System.Collections.IEnumerator.Reset()
        {
            _position = -1;
        }
    }
}

// Element class. 
public class Color
{
    public string Name { get; set; }
}

Итератор используется для выполнения пользовательских итераций по коллекции. Итератор может быть методом или методом доступа get. Итератор использует оператор Yield (Visual Basic) или yield return (C#) для возврата каждого элемента коллекции по одному за раз.

Итератор вызывается с помощью оператора For Each…Next (Visual Basic) или foreach (C#). Каждая итерация цикла For Each вызывает итератор. При достижении оператора Yield или yield return в итераторе возвращается выражение, и текущее расположение в коде сохраняется. При следующем вызове итератора выполнение возобновляется с этого места.

Для получения дополнительной информации см. Итераторы (C# и Visual Basic).

В следующем примере используется метод-итератор. Метод-итератор содержит оператор Yield или yield return, который находится внутри цикла For…Next (Visual Basic) или for (C#). В методе ListEvenNumbers каждая итерация тела оператора For Each создает вызов метода-итератора, который переходит к следующему оператору Yield или yield return.

private void ListEvenNumbers()
{
    foreach (int number in EvenSequence(5, 18))
    {
        Console.Write(number.ToString() + " ");
    }
    Console.WriteLine();
    // Output: 6 8 10 12 14 16 18
}

private static IEnumerable<int> EvenSequence(
    int firstNumber, int lastNumber)
{
    // Yield even numbers in the range. 
    for (var number = firstNumber; number <= lastNumber; number++)
    {
        if (number % 2 == 0)
        {
            yield return number;
        }
    }
}

Добавления сообщества

Корпорация Майкрософт проводит интернет-опрос, чтобы выяснить ваше мнение о веб-сайте MSDN. Если вы желаете принять участие в этом интернет-опросе, он будет отображен при закрытии веб-сайта MSDN.

Вы хотите принять участие?
Показ:
© 2015 Microsoft