Вопрос относительно IEnumerable и IEnumerator - PullRequest
7 голосов
/ 28 декабря 2010

Я использую следующий код, чтобы позволить myClass использовать foreach.Но я довольно новичок в программировании и испытываю некоторые трудности в понимании следующего кода.Я описал свои проблемы в комментариях.Буду признателен за предоставление информации.

    public class MyClass : IEnumerable<string> 
    {  
    //1) What is IEnumerator for?
        // Whats the difference between IEnumerator and IEnumerable
    public IEnumerator<string> GetEnumerator()     
    {
             yield return "first";         
             yield return "second";     
    }      
    //2) What is it for?  It just calls above method 
   IEnumerator IEnumerable.GetEnumerator()
         {
             return GetEnumerator(); 
         } 
    }
   //3) Lastly what benefits I have from implementing genetic interface 
   //IEnumerable<string> instead of just IEnumerable

Ответы [ 6 ]

11 голосов
/ 29 декабря 2010

В чем разница между IEnumerator и IEnumerable?

Ответ Джейсона хорош, но я подумал, что просто добавлю свое мнение об этом.Представьте, что у вас есть последовательность:

1, 1, 2, 3, 5, 8, 13, ...

Теперь представьте, что у вас есть стрелка, указывающая на какую-то позицию этой последовательности:

1, 1, 2, 3, 5, 8, 13, ...
         ^

«Стрелка» - это объект, который может выполнять две вещи,Во-первых, он может дать вам то, на что он указывает.Во-вторых, он может указывать на следующее.

IEnumerator - это стрелка.У него есть свойство Current, которое дает вам то, на что оно указывает.У него есть метод MoveNext (), который указывает на следующую вещь.

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

IEnumerable является фабрикой стрелок.У него есть метод GetEnumerator, который дает вам стрелку для первого элемента последовательности.

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

Каковы преимущества реализации универсального интерфейса IEnumerable вместо просто IEnumerable?

Предположим, что последовательность состоит из целых чисел.Если вы реализуете IEnumerable, тогда, когда вы говорите

foreach(int x in mysequence)

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

Предположим, что последовательность состоит из строк.Если вы реализуете IEnumerable<string>, то вы можете сказать:

string first = mysequence.First();

Если вы этого не сделаете, то вы должны сказать

string first = (string)mysequence.First();

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

6 голосов
/ 28 декабря 2010

1) Для чего IEnumerator? В чем разница между IEnumerator и IEnumerable?

IEnumerator - это интерфейс, представляющий методы, позволяющие перечислять последовательность. Разница между IEnumerator и IEnumerable заключается в том, что первое представляет контракт для объектов, которые позволяют перечислять последовательность, а второе представляет контракт для объектов, которые могут быть перечислены по последовательности.

public IEnumerator<string> GetEnumerator() {
         yield return "first";         
         yield return "second";     
}      


IEnumerator IEnumerable.GetEnumerator() {
    return GetEnumerator(); 
} 

2) Для чего он? Он просто вызывает метод выше.

Первый представляет собой реализацию метода GetEnumerator по контракту IEnumerable<string>. Последний представляет собой явную реализацию метода GetEnumerator по контракту IEnumerable. Проблема заключается в том, что оба контракта имеют метод с именем GetEnumerator, но с разными типами возврата, поэтому метод не может одновременно удовлетворить оба контракта (любой класс, реализующий IEnumerable<T>, должен также реализовать IEnumerable как IEnumerable<T> : IEnumerable). Последний вызывает реализацию IEnumerable<string>.GetEnumerator, поскольку это разумная реализация, которая возвращает IEnumerator как IEnumerator<string> : IEnumerator.

3) И наконец, какие преимущества я получаю от реализации универсального интерфейса IEnumerable<string> вместо просто IEnumerable?

Строгая типизация. Вы знаете, что элементы в последовательности IEnumerable<string> все являются экземплярами String, тогда как вы не знаете, что для IEnumerable, и в конечном итоге вы можете попытаться привести элемент последнего к экземпляру String, когда не может быть.

3 голосов
/ 28 декабря 2010

Это объявление для IEnumerable<T>:

public interface IEnumerable<out T> : IEnumerable
{
    IEnumerator<T> GetEnumerator();
}

У вас нет выбора, у вас есть для реализации неуниверсального интерфейса IEnumerable. Вы получите ошибку компиляции, если опустите реализацию IEnumerable.GetEnumerator (). Это багаж, оставшийся с тех дней .NET 1.x, когда дженерики еще не были доступны, и переходного периода для .NET 2.0, когда он должен был поддерживать взаимодействие со сборками .NET 1.x. Мы застряли с этим.

3 голосов
/ 28 декабря 2010

1) Для чего нужен IEnumerator?

IEnumerator - это настоящая рабочая часть с элементами MoveNext () и Current.

В чем разница междуIEnumerator и IEnumerable

IEnumerable - это интерфейс для коллекции, который сообщает о наличии GetEnumerator ().

2) [неуниверсальный GetEnumerator]?Он просто вызывает вышеуказанный метод

Неуниверсальный метод только для обратной совместимости.Обратите внимание, что он максимально удален из поля зрения при использовании явной реализации.Реализуйте это, потому что вы должны, а затем забыть об этом.

3) И наконец, какие преимущества я получаю от реализации генетического интерфейса IEnumerable вместо просто IEnumerable

При использовании с foreach преимущество невелико, поскольку foreach будет набирать-приведите циклическую переменную.Это позволит вам использовать var в foreach:

foreach (var s in myClassInstance)     // needs `IEnumerable<string>` 
foreach (string s in myClassInstance)  // works with  `IEnumerable` as well 

Но с IEnumerable<string> у вас также есть типобезопасный интерфейс с другими областями, особенно LINQ:

MyClass mc = new MyClass ();
string s = mc.FirstOrDefault();
0 голосов
/ 28 декабря 2010

Относительно третьего вопроса (зачем использовать дженерики?) Вот несколько ответов:

Следует ли использовать Generic Collection для повышения безопасности и производительности?

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

0 голосов
/ 28 декабря 2010

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

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

...