C# 访问修改后的闭包

发布于 2024-10-29 18:18:48 字数 687 浏览 1 评论 0原文

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

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

小…红帽 2024-11-05 18:18:48

问题在于:

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

变量 member 是对外部作用域中 member 变量的直接引用。虽然在上面的代码中您可能没有遇到问题,但当您在多个线程上运行代码或者没有立即在 Where 方法中计算 lambda 时,就会出现问题(例如例如,使用 IQueryable 而不是 IEnumerable)。

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

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

那么 C# 可以在称为“闭包”的构造中“捕获”该值,并将其传递给生成的方法。这将确保当 member 更改时,您将其传递给 Where 时期望的值不会更改。

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.

↙厌世 2024-11-05 18:18:48

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

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

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

玉环 2024-11-05 18:18:48

我想 member.SendMessage 可以修改 member

这就是修改 lambda 中使用的封闭变量

I suppose member.SendMessage could modify member

That's modifying a closed variable used in the lambda

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文