【问题标题】:C# Method (Yield) Return Path not detected未检测到 C# 方法(产量)返回路径
【发布时间】:2015-07-30 12:31:34
【问题描述】:

请考虑以下非常小的方法-:

IEnumerable<ObjectTest> CreateObjectList()
{
    bool aTest = false;
    ObjectTest anObject = null;
    if (aTest == true)
    {
        foreach (var item in aTestList)
        {
            yield return anObject;
        }
    }
}

我觉得这段代码不应该编译。由于布尔测试失败,有些路径不会返回。编译器应该报告-:

并非所有代码路径都返回值。

但事实并非如此——有人可以解释一下吗?

(.NET 4.0)

理查德

【问题讨论】:

  • 如果yield return 从未被命中,则返回不返回任何元素的迭代器。因此yield returns 可能永远不会返回null 的方法。
  • 如果它让你感觉更好,想象一下在最后一行有一个隐含的yield break;
  • HimBromBeere 非常感谢您的快速回复 - 您能否详细说明这是为什么以及在 C# 规范中的位置?
  • 10.14.4.1:遇到迭代器体结束时:枚举器对象的状态变为after。 MoveNext 方法向其调用者返回 false,表示迭代完成。
  • @RichardHill 第二个 :-) 你必须先理解 yield 的工作原理,然后一切就变得清晰了。您编写的代码由编译器进行了很大的转换。 “真正的”代码完全不同。因此,您观察到的是代码编写方式(以及 10.14.4.1)的自然副作用

标签: c# visual-studio yield


【解决方案1】:

因为yield return 在任何情况下都会返回一个迭代器,它保证永远不会返回null。因此yields 的方法总是有一个返回值,即迭代器。迭代器是否返回任何元素与这里无关。

也许thisthis 也可能很有趣。

【讨论】:

  • 好的 - 我明白了。这表明我并不完全了解产量,并且在使用它时要格外警惕,因为在我看来它会混淆代码。
  • 如果您链接到 MSDN 并指出它始终具有返回值,那将是一个完美的答案 ;)
【解决方案2】:

仅仅因为您使用的是yield return 并不意味着它涵盖了您的代码中超出yield return 范围的所有路径。

扩展 HimBromBeere 在 cmets 中所说的内容,请考虑以下内容:

IEnumerable<ObjectTest> CreateObjectList()
{
    bool aTest = false;
    ObjectTest anObject = null;
    List<ObjectTest> objects = new List<ObjectTest>();
    if (aTest == true)
    {
        foreach (var item in aTestList)
        {
            objects.Add(anObject);
        }

        return objects;
    }
}

这基本上就是您正在做的事情,只允许“从内部”处理代码的foreach 部分。上面的代码会抛出同样的错误。

正如 cmets 中所说,您缺少的部分是当您的 if (aTest == true) 无效时,您的其余代码不会返回任何内容。您可以维护上面的代码,但只需包括以下内容:

if (aTest == true)
{
    ...
}

yield break;

【讨论】:

  • 如果yield return nullyield break 会不会更好?因为它在完成后返回值 null 而不是仅仅结束文字
  • 太棒了 - 非常感谢您的回答,每个人都非常感谢您为此付出的时间和精力。
  • 是的,你是对的。我仔细检查了这一点,并在您发表评论时发现了这一点@manuchao。像我的编辑那样做yield break是正确的方法。
  • @juharr 是的,我知道。这就是为什么我在那里做了那个例子,然后说他会得到同样的错误。我这样做是为了显示一组没有 yield return 的等效代码,因为这似乎使 OP 感到困惑。
  • 但是 OP 没有收到错误。问题是“为什么我没有收到错误消息?”。
【解决方案3】:

请记住,您用 C# 编写的内容不一定是经过精确编译的内容。 yield 关键字是那些“语法糖”之一,不会导致您所写的内容。

尝试使用 .Net 反编译器(例如 JustCode 或 dotPeek)打开编译后的代码,并查看 IL(中间语言)结果。你会发现编译出来的不是你所期望的。

简而言之,yield return 只是“创建变量,填充它,然后返回它”的快捷方式。

你可以在这里看到更多的解释:http://www.dotnetperls.com/yield

【讨论】:

    【解决方案4】:

    想想如果aTestList在以下情况下为空会发生什么:

    IEnumerable<ObjectTest> CreateObjectList()
    {
        foreach (var item in aTestList)
        {
            yield return item;
        }
    }
    

    你知道会发生什么吗?枚举器不会产生任何东西。这正是您问题代码中发生的情况。

    【讨论】:

      猜你喜欢
      • 2023-03-26
      • 1970-01-01
      • 1970-01-01
      • 2015-11-28
      • 2015-03-27
      • 2020-12-26
      • 2021-10-02
      • 2014-07-16
      • 1970-01-01
      相关资源
      最近更新 更多