Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/285.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么返回IEnumerable的C#方法在返回列表时会起作用,而在生成列表时却不起作用?_C#_List_Lambda_Closures_Yield - Fatal编程技术网

为什么返回IEnumerable的C#方法在返回列表时会起作用,而在生成列表时却不起作用?

为什么返回IEnumerable的C#方法在返回列表时会起作用,而在生成列表时却不起作用?,c#,list,lambda,closures,yield,C#,List,Lambda,Closures,Yield,我有一个为浮动下拉菜单生成一组选项的方法。该方法的类型为IEnumerable 当我将值作为列表返回时,它工作正常。但是,当我一个接一个地生成它们时,每个项目都会为最后生成的项目运行useActlambda,即使它们都有正确的标签 有人能解释为什么会发生这种情况吗?为什么返回一个列表而不是一个接一个地生成项目很重要 public override IEnumerable<FloatMenuOption> GetFloatMenuChoicesFor(Pawn myPawn) {

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

当我将值作为
列表返回时,它工作正常。但是,当我一个接一个地生成它们时,每个项目都会为最后生成的项目运行
useAct
lambda,即使它们都有正确的标签

有人能解释为什么会发生这种情况吗?为什么返回一个
列表而不是一个接一个地生成项目很重要

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;
}
public override IEnumerable GetFloatMenuchoicefor(Pawn myPawn)
{
列表选项=新列表();
foreach(GetCommTargets()中的commTarget)
{
var localCommTarget=commTarget;
System.Action useAct=()=>
{
作业openJob=新作业();
openJob.commTarget=localCommTarget;
myPawn.MindHumanoid.TakeOrderedJob(openJob);
};
添加(新的FloatMenuOption(localCommTarget.GetLabel(),useAct));
}
返回选项;
//简单地注释掉上面的行并取消注释下面的两行会导致错误
//foreach(var选择加入选项)
//收益率选择;
}
在这两种情况下,选项都带有正确的标签(来自
localCommTarget.GetLabel()
)。但是,如果已生成,则它们都执行为列表中最后一项配置的useAct lambda,而如果作为列表返回,则它们各自执行自己的useAct lambda

为什么?

看看

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

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

您将获得成功。

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

您没有告诉我们错误是什么问题是,“当我一个接一个地生成它们时,每个项目都会为最后一个生成的项目运行useAct lambda”。我想我是在用
localCommTarget
变量这样做的。不是吗?因为localCommTarget在循环中被分离,所以每个lambda在它自己的作用域中应该有一个不同的副本。不管怎么说,为什么把它们添加到列表中会有所不同呢?在任何一种情况下,lambda都不会运行,直到localCommTarget达到其最终值。更重要的是,如果在循环中声明localCommTarget不起作用,我该如何解决这个问题?关键不是向列表中添加,而是将序列转换为列表,从而触发求值。