Есть существенная разница.
Выполнение GetByReYielding () будет выполняться отложенным образом (так как это блок итератора). Если вы использовали параметр в GetByReturn () или GetByReYielding () и проверили этот параметр во время выполнения на нулевое значение (или сделали какую-либо другую проверку), эта проверка будет выполнена немедленно при вызове GetByReturn (), но не сразу при вызове GetByReYielding () ! Проверка в GetByReYielding () будет выполняться отложенным способом, когда результат повторяется. - Это часто, ну, «слишком поздно». Смотрите здесь:
// Checks parameters early. - Fine. The passed argument will be checked directly when
// GetByReturn() is called.
IEnumerable<int> GetByReturn(IEnumerable<int> sequence)
{
if(null == sequence)
{
throw new ArgumentNullException("sequence");
}
return GetIterator();
}
// Checks parameters in a deferred manner. - Possibly not desired, it's "too" late. I.e. // when the
// result is iterated somewhere in a completely different location in your code the
// argument passed once will be checked.
IEnumerable<int> GetByReYielding(IEnumerable<int> sequence)
{
if(null == sequence)
{
throw new ArgumentNullException("sequence");
}
for(var item in GetIterator())
{
yield return item;
}
}
г. Skeet объяснил эту концепцию в http://msmvps.com/blogs/jon_skeet/archive/2010/09/03/reimplementing-linq-to-objects-part-2-quot-where-quot.aspx. Стандартные операторы запросов, представленные в .Net, используют неотложенные функции-оболочки (например, Where ()), которые проверяют параметры и затем вызывают основную функцию итератора (как я показал в моей реализации GetByReturn ()).
Надеюсь, это поможет.