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
精彩评论