Ну, здесь происходит пара вещей.
Во-первых, у вас есть не просто метод расширения , у вас есть метод расширения блок итератора - это то, что вы получаете, когда используете yield return
для автоматической реализации IEnumerable<>
контракт.
Звучит так, как будто вы хотите, чтобы ActiveAccounts()
вернул ноль IEnumerable<Account>
. На самом деле происходит то, что для международных представителей вы возвращаете нуль в качестве первого элемента IEnumerable . Я подозреваю, что вы можете
попытался использовать return null
там, но получил ошибку компилятора что-то вроде:
Ошибка: невозможно вернуть значение из итератора. Используйте оператор yield return для возврата значения или yield break для завершения итерации.
Если вы хотите, чтобы перечисляемое было пустым , то вам нужно yield break
вместо yield return null
. Обычно лучше возвращать пустую последовательность, поскольку это позволяет вызывающей стороне избегать проверки возвращаемого значения. Он также лучше подходит для таких технологий, как LINQ, которые используют композицию для сборки сложных запросов.
Вторая проблема заключается в том, что предварительное условие if( rep == null )
оценивается не при вызове ActiveAccounts()
, а при начале перечисления результата этого вызова. Это, вероятно, не то, что вы хотите - я думаю, вы хотите, чтобы предварительное условие было оценено немедленно.
Способ решения обеих этих проблем заключается в использовании двухэтапной реализации:
public static class AccountExt
{
// apply preconditions, return null for international reps
public static IEnumerable<Account> ActiveAccounts( this AccountRep rep )
{
if( rep == null )
throw new ArgumentNullException( "rep" );
if( rep.IsInternational )
return null;
// otherwise...
return ActiveAccountsImpl( rep );
}
// private implementation handles returning active accounts
private static IEnumerable<Account> ActiveAccountsImpl( AccountRep rep )
{
foreach( acc in rep.FetchAccounts() )
{
if( acc.IsActive )
yield return acc;
}
}
}
Если вы хотите использовать LINQ, вы можете избежать Impl
версии функции:
public static IEnumerable<Account> ActiveAccounts( this AccountRep rep )
{
if( rep == null )
throw new ArgumentNullException( "rep" );
if( rep.IsInternational )
return null;
// otherwise, using LINQ to filter the accounts...
return rep.FetchAccounts().Where( acc => acc.IsActive );
}
Подробнее о том, как блокировать итераторы , можно узнать здесь .