简体   繁体   English

C#访问修改后的闭包

[英]C# Access to modified closure

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

The problem is in: 问题在于:

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

The variable member is a direct reference to the member variable in the outer scope. 变量member是外部作用域中member变量的直接引用。 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 the Where method right away (for example, using IQueryable instead of IEnumerable ). 虽然您在上面的代码中可能没有遇到此问题,但是当您在多个线程上运行代码或者您没有立即在Where方法中评估lambda时(例如,使用IQueryable而不是IEnumerable )。

The reason this is a problem is that C# generates a method to then pass as a delegate to Where . 这是一个问题的原因是C#生成一个方法,然后作为委托传递给Where That method needs direct access to memeber . 该方法需要直接访问memeber If you were to assign the reference to another variable like this: 如果您要将引用分配给另一个变量,如下所示:

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

Then C# can "capture" that value in a construct called a "closure" and pass it to the generated method. 然后C#可以在称为“闭包”的构造中“捕获”该值,并将其传递给生成的方法。 This will ensure that when member changes, the value you expect it to be when you pass it to Where isn't changed. 这将确保当member更改时,您将其传递给Where时所期望的值不会更改。

The part resharper complains about is e.Team.Where(partner => partner != member).ToList() , as the referenced member will be changed. 部分e.Team.Where(partner => partner != member).ToList()抱怨的是e.Team.Where(partner => partner != member).ToList() ,因为引用的member将被更改。 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 the IEnumerable<T> . 注意:您不必使用ToList() ,这会强制急切评估IEnumerable<T> Simply iterate over e.Team.Where(partner => partner != member) . 只需遍历e.Team.Where(partner => partner != member)

I suppose member.SendMessage could modify member 我想member.SendMessage可以修改member

That's modifying a closed variable used in the lambda 那是在修改lambda中使用的闭合变量

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM