Поделиться через


Практическое руководство. Доступ к классу коллекции с помощью оператора foreach (Руководство по программированию в C#)

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

Примечание

Этот пример представляет рекомендованный способ, только если использование универсального класса коллекции невозможно.Для примера реализации типобезопасного универсального класса коллекции, поддерживающего тип IEnumerable<T>, см. раздел Практическое руководство. Создание блока итератора для общего списка (Руководство по программированию на C#).

В примере следующий сегмент кода использует класс Tokens для разделения предложения "Это предложение-образец." на токены с помощью разделителей " " и "-". Затем код отображает эти токены с помощью оператора foreach.

Tokens f = new Tokens("This is a sample sentence.", new char[] {' ','-'});

// Display the tokens.
foreach (string item in f)
{
    System.Console.WriteLine(item);
}

Пример

По сути, класс Tokens использует массив для хранения токенов. Поскольку массивы реализуют типы IEnumerator и IEnumerable, пример кода может использовать методы перечисления массивов (GetEnumerator, MoveNext, Reset и Current) вместо определения их в классе Tokens. Определения методов содержатся в примере для уточнения способа их определения и предназначения каждого из них.

using System.Collections;

// Declare the Tokens class. The class implements the IEnumerable interface.
public class Tokens : IEnumerable
{
    private string[] elements;

    Tokens(string source, char[] delimiters)
    {
        // The constructor parses the string argument into tokens.
        elements = source.Split(delimiters);
    }

    // The IEnumerable interface requires implementation of method GetEnumerator.
    public IEnumerator GetEnumerator()
    {
        return new TokenEnumerator(this);
    }


    // Declare an inner class that implements the IEnumerator interface.
    private class TokenEnumerator : IEnumerator
    {
        private int position = -1;
        private Tokens t;

        public TokenEnumerator(Tokens t)
        {
            this.t = t;
        }

        // The IEnumerator interface requires a MoveNext method.
        public bool MoveNext()
        {
            if (position < t.elements.Length - 1)
            {
                position++;
                return true;
            }
            else
            {
                return false;
            }
        }

        // The IEnumerator interface requires a Reset method.
        public void Reset()
        {
            position = -1;
        }

        // The IEnumerator interface requires a Current method.
        public object Current
        {
            get
            {
                return t.elements[position];
            }
        }
    }


    // Test the Tokens class.
    static void Main()
    {
        // Create a Tokens instance.
        Tokens f = new Tokens("This is a sample sentence.", new char[] {' ','-'});

        // Display the tokens.
        foreach (string item in f)
        {
            System.Console.WriteLine(item);
        }
    }
}
/* Output:
    This
    is
    a
    sample
    sentence.  
*/

В языке C# классу коллекции необязательно реализовывать IEnumerable и IEnumerator для совместимости с foreach. Если в классе содержатся обязательные члены GetEnumerator, MoveNext, Reset и Current, он будет работать с оператором foreach. Пропуск интерфейсов имеет преимущество, поскольку позволяет определить тип возврата для Current, который более специфичен, чем тип Object. Это повышает типобезопасность.

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

// Change the Tokens class so that it no longer implements IEnumerable.
public class Tokens
{
    // . . .

    // Change the return type for the GetEnumerator method.
    public TokenEnumerator GetEnumerator()
    {   }

    // Change TokenEnumerator so that it no longer implements IEnumerator.
    public class TokenEnumerator
    {
        // . . .

        // Change the return type of method Current to string.
        public string Current
        {   }
    }
 }

Поскольку Current возвращает строку, компилятор может определить, когда используется несовместимый тип в операторе foreach, как показано в следующем примере.

// Error: Cannot convert type string to int.
foreach (int item in f)  

Недостатком пропуска типов IEnumerable и IEnumerator является то, что класс коллекции больше не может взаимодействовать с операторами foreach или эквивалентными операторами из других языков среды CLR.

См. также

Ссылки

Массивы (Руководство по программированию на C#)

Классы коллекций (Руководство по программированию в C#)

System.Collections.Generic

Основные понятия

Руководство по программированию на C#

Другие ресурсы

Справочник по C#

Журнал изменений

Дата

Журнал

Причина

Март 2011

Отредактировано для повышения ясности.

Улучшение информации.