C#访问修改后的闭包

时间:2011-04-02 23:45:10

标签: c# 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);
}

我通过resharper获得“访问修改后的闭包”警告,我想知道这段代码有什么问题,因为我在内循环中所做的只是发送消息?

3 个答案:

答案 0 :(得分:13)

问题在于:

e.Team.Where(partner => partner != member)

变量member是对外部范围中member变量的直接引用。虽然您在上面的代码中可能没有遇到此问题,但是当您在多个线程上运行代码或者您没有立即在Where方法中评估lambda时(例如,使用IQueryable代替IEnumerable)。

这是一个问题的原因是C#生成一个方法然后作为委托传递给Where。该方法需要直接访问memeber。如果您要将引用分配给另一个变量,如下所示:

var m = member;
// ...
e.Team.Where(partner => partner != m);

然后C#可以在一个名为“closure”的构造中“捕获”该值,并将其传递给生成的方法。这将确保在member更改时,您将其传递给Where时所期望的值不会更改。

答案 1 :(得分:2)

部分resharper抱怨的是e.Team.Where(partner => partner != member).ToList(),因为引用的member会被更改。在这种情况下,这不是问题,但在其他情况下,这可能是一个问题。

注意:您不必使用ToList(),这会强制评估IEnumerable<T>。只需迭代e.Team.Where(partner => partner != member)

答案 2 :(得分:0)

我认为member.SendMessage可以修改member

那是修改lambda中使用的闭合变量