Well, there's a couple of things going on here.
First, you don't just have an extension method, you have an extension method iterator block - that's what you get when you use yield return
to automatically implement the IEnumerable<>
contract.
It sounds like what you want to have happen is for ActiveAccounts()
to return a null IEnumerable<Account>
. What's actually happening is that for international reps you are returning null as the first element of the IEnumerable. I suspect that you may
have tried using return null
there but got a compiler error something like:
Error: Cannot return a value from an iterator. Use the yield return statement to return a value, or yield break to end the iteration.
If what you intended is for the enumerable to be empty, what you want is yield break
instead of yield return null
. It's actually a better idea, generally, to return an empty sequence, as it allows the caller to avoid checking the return value. It also player nicer with technologies like LINQ, which use composition to assemble complex queries.
The second issue is that the if( rep == null )
precondition is not evaluated when you call ActiveAccounts()
, but rather when you begin to enumerate the result of that call. That's probably not what you want - I'd imagine you want the precondition evaluated immediately.
The way you resolve both these problems is to use a two-stage implementation:
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;
}
}
}
If you're willing to use LINQ, to can avoid the Impl
version of the function:
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 );
}
You can learn more about how iterator blocks here.