C # Доступ к измененному закрытию - PullRequest
7 голосов
/ 03 апреля 2011
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. Мне было интересно, что же такого не так с этим кодом, так как все, что я делаю во внутреннем цикле, это отправляет сообщение?

Ответы [ 3 ]

13 голосов
/ 03 апреля 2011

Проблема в:

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

Переменная member является прямой ссылкой на переменную member во внешней области видимости. Хотя у вас может не быть проблем с этим в приведенном выше коде, это проблематично, если вы выполняете код в нескольких потоках или если вы не оцениваете лямбда-выражения в методе Where сразу (например, при использовании IQueryable вместо IEnumerable).

Причина этой проблемы в том, что C # генерирует метод, который затем передается в качестве делегата Where. Этот метод требует прямого доступа к memeber. Если вы должны были присвоить ссылку на другую переменную, как это:

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

Тогда C # может «захватить» это значение в конструкции, называемой «замыканием», и передать ее сгенерированному методу. Это гарантирует, что при изменении member значение, которое вы ожидаете получить при передаче в Where, не изменится.

2 голосов
/ 03 апреля 2011

Компонент, на который жалуется деталь, это e.Team.Where(partner => partner != member).ToList(), так как ссылка member будет изменена.В этом случае это не проблема, но в других случаях это может быть проблемой.

Примечание: вам не нужно использовать ToList(), что заставляет нетерпеливо оценивать IEnumerable<T>,Просто переберите e.Team.Where(partner => partner != member).

0 голосов
/ 03 апреля 2011

Полагаю, member.SendMessage может изменить member

Это изменение закрытой переменной, используемой в лямбде

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...