为什么返回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不起作用,我该如何解决这个问题?关键不是向列表中添加,而是将序列转换为列表,从而触发求值。