代码之家  ›  专栏  ›  技术社区  ›  Mike Two

yield break等同于返回可枚举的<t>。从返回IEnumerable<t>的方法中为空

c#
  •  37
  • Mike Two  · 技术社区  · 16 年前

    这两种方法在我看来是一样的

    public IEnumerable<string> GetNothing()
    {
        return Enumerable.Empty<string>();
    }
    
    public IEnumerable<string> GetLessThanNothing()
    {
        yield break;
    }
    

    我已经在测试场景中对每一个进行了分析,我看不出速度上有什么有意义的差异,但是 yield break 版本稍快。

    有什么理由要用一个来代替另一个吗?一个比另一个容易读吗?有没有行为上的差异会影响到打电话的人?

    5 回复  |  直到 9 年前
        1
  •  33
  •   JaredPar    16 年前

    如果希望始终返回空的可枚举项,则使用 Enumerable.Empty<string>() 语法更具声明性。

    这里的性能差异几乎肯定不显著。在这里,我将重点放在可读性而不是性能上,直到一个分析器向您显示这是一个问题。

        2
  •  11
  •   Fede    16 年前

    IEnumerable<T> 方法与 yield break yield return 在他们的身体里被转化为状态机。在这种方法中,你不能把收益率和传统收益率混合起来。我的意思是,如果你在方法的某个部分产生了一些结果,你就不能在另一个部分返回一个icollection。

    另一方面,假设您正在实现一个返回类型为 IEnumerable<t> 通过向集合中添加项,然后返回集合的只读副本。如果由于某种原因您只想返回一个空集合,则不能执行 产量突破 . 你能做的就是回来 Enumerable.Empty<T>() .

    如果你已经分析了这两种方法,并且没有显著的变化,那么你可以忘记它:)

        3
  •  7
  •   Edward Brey    9 年前

    我已经在测试场景中对每一个进行了分析,我看不出速度上有什么有意义的差异,但是收益率突破版本稍快一些。

    我猜您的分析测试不包括程序启动速度。这个 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;
    }
    

    EmptyEnumerable 通过惰性地创建静态空数组来工作。也许检查是否需要创建数组是原因 空可数 yield break 在孤立的基准测试中,但是要克服启动惩罚可能需要大量的迭代,而且任何一种方式都不太可能在整体上引人注目,即使在“千倍性能剪纸的死亡”场景中也是如此。

        4
  •  5
  •   greenoldman    15 年前

    有趣的是,今天早上我读到这篇文章,几个小时后我被这个例子击中了——当你有更多的代码时,我发现了区别:

    public static IEnumerable<T> CoalesceEmpty<T>(IEnumerable<T> coll)
    {
        if (coll == null)
            return Enumerable.Empty<T>();
        else
             return coll;
    }
    

    您不能将第一个返回更改为yield break,因为还必须将第二个返回更改为较长的版本。

        5
  •  1
  •   bdukes Jon Skeet    16 年前

    看来 yield break 将实例化的对象至少比 return Enumerable.Empty<string>() 会的。另外,可能有一些检查会使 产量突破 . 如果没有其他的,那就是少了一个函数包装器,你的堆栈可以通过它来检测,虽然不明显。

    不过,我同意另一个发帖的回答,空是“首选”的方式。