Практическое руководство. Доступ к классу коллекции с помощью оператора foreach (Руководство по программированию в C#)
Обновлен: Ноябрь 2007
В следующем примере показана запись неуниверсального класса коллекции, который можно использовать с оператором foreach. Класс является средством разметки строки, подобно функции библиотеки времени выполнения C strtok_s.
Примечание. |
---|
Этот пример представляет рекомендованный способ, только если использование универсального класса коллекции невозможно. Универсальные шаблоны поддерживаются языком C# и платформой .NET Framework версии 2.0 или более поздней. Пример реализации строго типизированного универсального класса коллекции, который поддерживает IEnumerable<T> и тем самым предупреждает возникновение проблем, описываемых далее в документе, см. в разделе Практическое руководство. Создание блока итератора для общего списка (руководство по программированию в C#). |
В следующем примере Tokens разбивает предложение "This is a sample sentence." на маркеры, используя в качестве разделителей ' ' и '-', и перечисляет эти маркеры с помощью оператора foreach.
Tokens f = new Tokens("This is a sample sentence.", new char[] {' ','-'});
foreach (string item in f)
{
System.Console.WriteLine(item);
}
Внутренне Tokens использует массив, который реализует IEnumerator и сам IEnumerable. В этом примере методы перечисления массива могли бы использоваться кодом как собственные, однако это изменило бы цель примера.
В C# отсутствует крайняя необходимость наследования класса коллекции от IEnumerable и IEnumerator для обеспечения совместимости с foreach. Пока для класса имеются необходимые члены GetEnumerator, MoveNext, Reset и Current, он будет работать с оператором foreach. Пропуск интерфейсов позволяет определять возвращаемый тип Current более точно, чем Object, обеспечивающий строгую типизацию.
Например, в примере кода, приведенном ранее в этом разделе, измените следующие строки.
// No longer inherits from IEnumerable:
public class Tokens
// Doesn't return an IEnumerator:
public TokenEnumerator GetEnumerator()
// No longer inherits from IEnumerator:
public class TokenEnumerator
// Type-safe: returns string, not object:
public string Current
Теперь, поскольку Current возвращает строку, компилятор может обнаружить использование в операторе foreach несовместимого типа.
// Error: cannot convert string to int:
foreach (int item in f)
Недостатком пропуска IEnumerable и IEnumerator является отсутствие взаимодействия класса коллекции с операторами foreach или их эквивалентами в других языках, совместимых со средой CLR.
Самые подходящие возможности — строгую типизацию в C# и взаимодействие с другими языками, совместимыми с CLR — можно выбрать путем наследования от IEnumerable и IEnumerator и явной реализации интерфейса, как показано в следующем примере.
Пример
using System.Collections;
// Declare the Tokens class:
public class Tokens : IEnumerable
{
private string[] elements;
Tokens(string source, char[] delimiters)
{
// Parse the string into tokens:
elements = source.Split(delimiters);
}
// IEnumerable Interface Implementation:
// Declaration of the GetEnumerator() method
// required by IEnumerable
public IEnumerator GetEnumerator()
{
return new TokenEnumerator(this);
}
// Inner class implements IEnumerator interface:
private class TokenEnumerator : IEnumerator
{
private int position = -1;
private Tokens t;
public TokenEnumerator(Tokens t)
{
this.t = t;
}
// Declare the MoveNext method required by IEnumerator:
public bool MoveNext()
{
if (position < t.elements.Length - 1)
{
position++;
return true;
}
else
{
return false;
}
}
// Declare the Reset method required by IEnumerator:
public void Reset()
{
position = -1;
}
// Declare the Current property required by IEnumerator:
public object Current
{
get
{
return t.elements[position];
}
}
}
// Test Tokens, TokenEnumerator
static void Main()
{
// Testing Tokens by breaking the string into tokens:
Tokens f = new Tokens("This is a sample sentence.", new char[] {' ','-'});
foreach (string item in f)
{
System.Console.WriteLine(item);
}
}
}
/* Output:
This
is
a
sample
sentence.
*/
См. также
Основные понятия
Руководство по программированию в C#
Ссылки
Массивы (Руководство по программированию на C#)
Классы коллекций (руководство по программированию в C#)