开发者

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?


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. 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).

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 to member. 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. This will ensure that when member changes, the value you expect it to be when you pass it to Where isn't changed.


The part resharper complains about is e.Team.Where(partner => partner != member).ToList(), as the referenced member 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 the IEnumerable<T>. Simply iterate over e.Team.Where(partner => partner != member).


I suppose member.SendMessage could modify member

That's modifying a closed variable used in the lambda

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜