2010-12-28 3 views
7

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

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 
+3

Я позволю john skeet ответить на этот вопрос –

+4

@ Хасан: Я боюсь, что он сделает с вами, написав свое имя. – JYelton

ответ

11

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

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

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

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

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

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

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(); 

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

+2

Nice метафора со стрелкой концепции. Также стоит упомянуть, что один общий побочный эффект этой модели заключается в том, что изменение начального набора начинается, как правило, делает недействительными все «стрелки», указывающие на него. – LBushkin

+0

Незначительная заметка о _ "GetEnumerator, которая дает вам стрелку для первого элемента последовательности" _: Согласно [MSDN] (http://msdn.microsoft.com/en-us/library/system.collections.ienumerable .getenumerator (v = vs.110) .aspx), он дает вам стрелку, указывающую на какую-то неопределенную вещь, прежде всего. – jan

+0

@jan: Хорошая точка! –

0

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

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

6

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

1) Что такое IEnumerator?

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

Что разница между IEnumerator и IEnumerable

IEnumerable представляет собой интерфейс для сбора, чтобы сигнализировать, что она имеет GetEnumerator().

2) [non-generic GetEnumerator] Для чего? Он просто называет метод выше

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

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

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

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(); 
3

Это декларация IEnumerable<T>:

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

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

Смежные вопросы