这两种方法似乎对我来说都是一样的
public IEnumerable<string> GetNothing()
{
return Enumerable.Empty<string>();
}
public IEnumerable<string> GetLessThanNothing()
{
yield break;
}
Run Code Online (Sandbox Code Playgroud)
我在测试场景中分析了每一个,我没有看到速度上有意义的差异,但yield break
版本稍微快一些.
是否有任何理由使用一个而不是另一个?一个比另一个更容易阅读吗?是否存在对呼叫者有影响的行为差异?
Jar*_*Par 36
如果你打算总是返回一个空的枚举,那么使用Enumerable.Empty<string>()
语法更具说明性恕我直言.
这里的性能差异几乎肯定不显着.我将重点关注性能的可读性,直到分析器显示它是一个问题.
Fed*_*ede 14
IEnumerable<T>
身体yield break
或yield return
体内的方法转化为状态机.在这种方法中,您不能将收益率收益与传统收益混合.我的意思是,如果你在方法的某些部分产生某些东西,你就不能在另一个方法中返回ICollection.
另一方面,假设您IEnumerable<T>
通过向集合添加项目,然后返回集合的只读副本来实现具有返回类型的方法.如果由于某种原因你只想返回一个空的集合,你就不能做了yield break
.你所能做的就是回归Enumerable.Empty<T>()
.
如果你已经对两种方式进行了分析,并且没有重大变化,那么你可以忘掉它:)
我在测试场景中分析了每一个,我没有看到速度上有意义的差异,但是收益中断版本稍快一些.
我猜你的分析测试不包括程序启动速度.该yield
构造通过为您生成一个类来工作.当它提供您需要的逻辑时,这个额外的代码很棒,但如果没有,它只会增加磁盘I/O,工作集大小和JIT时间.
如果在ILSpy中打开包含测试方法的程序并关闭枚举器反编译,您将找到一个以<GetLessThanNothing>d__0
十几个成员命名的类.它的MoveNext
方法如下:
bool IEnumerator.MoveNext()
{
int num = this.<>1__state;
if (num == 0)
{
this.<>1__state = -1;
}
return false;
}
Run Code Online (Sandbox Code Playgroud)
EmptyEnumerable
通过懒惰地创建静态空数组来工作.也许检查是否需要创建数组的原因EmptyEnumerable
是比yield break
单独的基准测试慢,但是可能需要大量的迭代来克服启动惩罚,并且无论哪种方式总体上都不太明显,即使在"一千个穿孔剪纸死亡的情景.
有趣的是,我今天早上看了这篇文章,几个小时后我被这个例子击中 - 当你有更多的代码时发现了区别:
public static IEnumerable<T> CoalesceEmpty<T>(IEnumerable<T> coll)
{
if (coll == null)
return Enumerable.Empty<T>();
else
return coll;
}
Run Code Online (Sandbox Code Playgroud)
您不能将第一个返回更改为yield break,因为您还必须更改第二个返回(更长版本).