为什么C#方法在返回List时返回IEnumerable而不是在它返回时产生?

时间:2014-03-11 05:09:56

标签: c# list lambda closures yield

我有一个为浮动下拉菜单生成一组选项的方法。该方法的类型为IEnumerable<FloatMenuOption>

当我将值作为List返回时,它可以正常工作。但是当我逐一放弃它们时,每个项目都运行useAct lambda,最后一个产生,尽管它们都有正确的标签。

任何人都可以解释为什么会这样吗?为什么要返回List而不是逐个产生项目?

public override IEnumerable<FloatMenuOption> GetFloatMenuChoicesFor(Pawn myPawn)
{
    List<FloatMenuOption> options = new List<FloatMenuOption>();
    foreach ( Communicable commTarget in GetCommTargets() )
    {
        var localCommTarget = commTarget;

        System.Action useAct = () =>
        {
        Job openJob = new Job();
        openJob.commTarget = localCommTarget;
        myPawn.MindHumanoid.TakeOrderedJob(openJob);
        };

        options.Add( new FloatMenuOption(localCommTarget.GetLabel(), useAct) );
    }

    return options;

    //Simply commenting out the above line and uncommenting the two below causes the error
//  foreach (var opt in options)
//      yield return opt;
}

在任何一种情况下,选项都会出现正确的标签(来自localCommTarget.GetLabel())。但是,如果屈服了,它们都会为列表中的最后一项配置useAct lambda,而如果作为列表返回,它们每个都会执行自己的useAct lambda。

为什么?

2 个答案:

答案 0 :(得分:1)

查看Captured variable in a loop in C#

我相信如果你将for循环更改为:

foreach (var opt in options)
{
   var capturedOpt = opt;
   yield return capturedOpt;
}

你会成为金色的。

答案 1 :(得分:0)

在您的实现中,如果您的代码生成结果而不是将它们添加到列表中,则仅使用localCommTarget的最后一个赋值。这样做的原因是lambda表达式的执行被推迟到对返回的实际访问。换句话说,不同的回报策略的执行顺序是不同的。