我不能做我想做的事。我只想要非国际代表的帐户。但是当我调用 ActiveAccounts() 时,我并没有得到 null,而是得到了一个可枚举的对象,其中包含 null。我在这里做错了什么?请帮忙。
public static class AccountExt
{
public static IEnumerable<Account> ActiveAccounts( this AccountRep rep )
{
if( rep == null )
throw new ArgumentNullException();
if( rep.IsInternational )
yield return null;
foreach( var acc in rep.FetchAccounts() )
{
if( acc.IsActive )
yield return acc;
}
}
}
最佳答案
好吧,这里发生了几件事。
首先,您不仅有一个扩展方法,您还有一个扩展方法迭代器 block - 这就是您使用 yield return
时得到的结果自动执行 IEnumerable<>
契约(Contract)。
听起来您想要发生的是 ActiveAccounts()
返回空 IEnumerable<Account>
.实际发生的情况是,对于国际代表,您将返回 null 作为 IEnumerable 的第一个元素。我怀疑你可能
试过使用return null
那里有一个编译器错误,例如:
Error: Cannot return a value from an iterator. Use the yield return statement to return a value, or yield break to end the iteration.
如果您的目的是让枚举为空,那么您需要的是 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 );
}
您可以了解有关迭代器如何阻塞 here 的更多信息.
关于c# - 为什么这种扩展方法不起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2248794/