На stackoverflow задали вопрос про yield return. Ну и т.к. пример для понимания что это за зверь написал, то пусть он и в этом блоге полежит. Под катом два примера, как реализовать класс реализующий IEnumerable или IEnumerable классически и при помощи yield return. Для тех кто не в курсе, foreach и методы Linq работают с классами реализующими эти интерфейсы.

Итак, давайте посмотрим два примера в которых будут возвращаться четные числа от 2 до 10. Первый будем реализовывать класс без yield return:

class MyCollection : IEnumerable, IEnumerator
{
int _current = 0;

public int Current
{
get
{
if (_current <= 10)
{
return _current;
}
throw new IndexOutOfRangeException();
}
}

object IEnumerator.Current => Current;

public bool MoveNext()
{
if (_current < 10)
{
_current
+= 2;
return true;
}
return false;
}

public void Reset()
{
_current
= 0;
}

public void Dispose()
{

}

public IEnumerator GetEnumerator()
{
return new MyCollection();
}

IEnumerator IEnumerable.GetEnumerator()
{
return new MyCollection();
}
}
Как видно (ну я на это как минимум надеюсь), у нас класс кроме интерфейса IEnumerable реализует еще и интерфейс IEnumerator. В чем разница: 
IEnumerable — говорит: «Я могу предоставить способ последовательного перебора коллекции». И именно в этом интерфейсе объявлены методы GetEnumerator.
IEnumerator — говорит: «Я могу отдать текущий элемент, перейти к следующему, вернуться в начало». К этому интерфейсу принадлежат все остальные методы в примере.
В чем идея, в цикле foreach один раз вызывается метод GetEnumerator, а уже в полученном объекте, до тех пор, пока метод MoveNext не вернет false, берется current и записывается в переменную цикла. В общем виде последовательность такая:
var items = <объект поддерживающий IEnumerable>.GetEnumerator();
пока (items.MoveNext())
{
  var item = items.Current;
  // Здесь полезная работа
}
Надеюсь все понятно. Теперь, как можно переписать этот пример, при помощи синтаксического сахара yield return:
class MyCollection : IEnumerable
{
public IEnumerator GetEnumerator()
{
for (int i = 2; i <= 10; i += 2)
{
yield
return i;

}
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Обратите внимание насколько уменьшился код и на то, что нам не пришлось реализовывать второй интерфейс, все это оказалось спрятано внутри синтаксического сахара yield return. При вызове вот такого кода, что для первого, что для второго примера:
static void Main(string[] args)
{
foreach (var item in new MyCollection())
{
Console.WriteLine(item);
}
Console.ReadKey();
}
Вы увидите на консоли четные числа от 2 до 10. Как писать, выбирать вам.