C# 访问修改后的闭包
public virtual void OnRegistrationJoin(RegistrationJoinEventArgs e)
{
foreach (Mobile member in e.Team)
{
member.SendMessage(1161, "You join the {0}.", EventFullName);
if (e.Team.Count > 1)
{
Joinees.Remove(member);
member.SendMessage(1161, "Your team formation is:");
int i = 0;
foreach (Mobile parter in e.Team.Where(partner => partner != member).ToList())
{
member.SendMessage(1150, "{0}: {1}.", ++i, partner.Name);
}
}
}
Members.Add(e.Team);
}
我收到 resharper 的“访问修改后的闭包”警告,我想知道这段代码有什么问题,因为我在内循环中所做的只是发送消息?
public virtual void OnRegistrationJoin(RegistrationJoinEventArgs e)
{
foreach (Mobile member in e.Team)
{
member.SendMessage(1161, "You join the {0}.", EventFullName);
if (e.Team.Count > 1)
{
Joinees.Remove(member);
member.SendMessage(1161, "Your team formation is:");
int i = 0;
foreach (Mobile parter in e.Team.Where(partner => partner != member).ToList())
{
member.SendMessage(1150, "{0}: {1}.", ++i, partner.Name);
}
}
}
Members.Add(e.Team);
}
I get "access to modified closure" warning by resharper, I was wondering what's so wrong with this code, since all I do in the inner loop is send a message?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
问题在于:
变量
member
是对外部作用域中member
变量的直接引用。虽然在上面的代码中您可能没有遇到问题,但当您在多个线程上运行代码或者没有立即在Where
方法中计算 lambda 时,就会出现问题(例如例如,使用IQueryable
而不是IEnumerable
)。这是一个问题的原因是 C# 生成一个方法,然后作为委托传递给
Where
。该方法需要直接访问member
。如果要将引用分配给另一个变量,如下所示:那么 C# 可以在称为“闭包”的构造中“捕获”该值,并将其传递给生成的方法。这将确保当
member
更改时,您将其传递给Where
时期望的值不会更改。The problem is in:
The variable
member
is a direct reference to themember
variable in the outer scope. While you might not have a problem with this in the above code, it is problematic when you are running the code on multiple threads or if you aren't evaluating the lambda in theWhere
method right away (for example, usingIQueryable
instead ofIEnumerable
).The reason this is a problem is that C# generates a method to then pass as a delegate to
Where
. That method needs direct access tomember
. If you were to assign the reference to another variable like this:Then C# can "capture" that value in a construct called a "closure" and pass it to the generated method. This will ensure that when
member
changes, the value you expect it to be when you pass it toWhere
isn't changed.resharper 抱怨的部分是
e.Team.Where(partner =>partner != member).ToList()
,因为引用的member
将被更改。在这种情况下,这不是问题,但在其他情况下,这可能是一个问题。注意:您不必使用
ToList()
,这会强制急切地评估IEnumerable
。只需迭代e.Team.Where(partner =>partner != member)
即可。The part resharper complains about is
e.Team.Where(partner => partner != member).ToList()
, as the referencedmember
will be changed. In this case, this isn't a problem, but in other cases, this can be a problem.Note: you don't have to use
ToList()
, which forces eager evaluation of theIEnumerable<T>
. Simply iterate overe.Team.Where(partner => partner != member)
.我想
member.SendMessage
可以修改member
这就是修改 lambda 中使用的封闭变量
I suppose
member.SendMessage
could modifymember
That's modifying a closed variable used in the lambda