2011-04-02 65 views
6
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得到“访问修改后的闭包”警告,我想知道这段代码有什么问题,因为我在内部循环中做的所有事情都是发送消息?C#访问被修改的闭包

+1

[Access to Modified Closure](http://stackoverflow.com/questions/235455/access-to-modified-closure)和其他几个可能的重复。 – adrianbanks 2011-04-03 00:13:00

回答

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#可以以被称为“封闭”构建体“捕获”该值并把它传递给生成的方法。这将确保当member发生变化时,您将它传递给Where时的值不会改变。

+0

+1:最终,我认为对大多数人来说,最大的问题是推迟执行。 – vcsjones 2011-04-02 23:49:34

+0

通过var closureMember = member轻松修复。并在LINQ中使用closureMember。 – 2011-04-02 23:50:49

+0

@Femaref - 但它是变化的参考,这是问题,而不是变化的实例。 – codekaizen 2011-04-02 23:53:06

0

我想member.SendMessage可以修改member

这是修改的拉姆达

+0

不是。问题是外部的foreach循环修改了lambda中绑定的'member'变量。 – Femaref 2011-04-02 23:53:00

2

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

注意:您不必使用ToList(),这迫使迫切渴望评估IEnumerable<T>。只需遍历e.Team.Where(partner => partner != member)即可。