Вопрос о foreach и делегатах

Я прочитал этот ответ через 8 лет и чувствую, что принятый ответ от @Robert, как правило, правильный, но математически неправильный.

Чтобы обеспечить требования к выравниванию элементов конструкции, выравнивание структуры должно быть, по крайней мере, таким же строгим, как наименьшее общее кратное выравнивания ее элементов . Рассмотрим странный пример, где требования к выравниванию элементов равны 4 и 10; в этом случае выравнивание структуры - это LCM (4, 10), которое равно 20, а не 10. Конечно, странно видеть платформы с таким требованием выравнивания, которое не является степенью 2, и, таким образом, для всех практических случаев , выравнивание структуры равно максимальному выравниванию ее членов.

Причина этого заключается в том, что, только если адрес структуры начинается с LCM выравнивания его элементов, выравнивание всех элементов может быть выполнено, и заполнение между элементами и концом структуры не зависит от начальный адрес.

Обновление: Как указал @chqrlie в комментарии, стандарт C не допускает нечетных значений выравнивания. Однако этот ответ все еще доказывает, почему структурное выравнивание является максимальным из выравниваний его элементов, просто потому, что максимум оказывается наименьшим общим кратным, и, таким образом, элементы всегда выровнены относительно общего множественного адреса.

5
задан FerranB 21 October 2009 в 12:48
поделиться

5 ответов

ОБНОВЛЕНИЕ: Подробный анализ и комментарии по этому вопросу здесь:

http://ericlippert.com/2009/11/12/closing-over-the-loop-variable- считается-вредно-часть-первая /


Об этой проблеме очень часто сообщается; обычно об этом сообщают как об ошибке компилятора, но на самом деле компилятор поступает правильно в соответствии со спецификацией. Анонимные функции закрывают переменные , а не значения , и существует только одна переменная цикла foreach. Следовательно, каждая лямбда закрывает одну и ту же переменную и, следовательно, получает текущее значение этой переменной.

Это удивляет почти всех и приводит к большой путанице и множеству отчетов об ошибках. Мы рассматриваем изменение спецификации и реализации для гипотетической будущей версии C # так, чтобы переменная цикла логически объявлялась внутри конструкции цикла, давая «свежую» переменную каждый раз в цикле.

Это будет критическое изменение , но я подозреваю, что количество людей, которые зависят от этого странного поведения, довольно мало. Если у вас есть мнение по этому поводу, не стесняйтесь добавлять комментарии к сообщениям в блоге, упомянутым выше в обновлении. Спасибо!

не стесняйтесь добавлять комментарии к сообщениям в блоге, упомянутым выше в обновлении. Спасибо!

не стесняйтесь добавлять комментарии к сообщениям в блоге, упомянутым выше в обновлении. Спасибо!

11
ответ дан 18 December 2019 в 09:50
поделиться

Второй фрагмент кода - это лучший способ добиться того, чтобы все остальное оставалось неизменным.

Тем не менее, можно создать свойство для Something , который занимает элемент . В свою очередь, код события может получить доступ к этому элементу у отправителя события, или он может быть включен в аргументы события для события. Следовательно, устраняется необходимость в закрытии.

Лично я добавил «Устранение ненужного закрытия» в качестве полезного рефакторинга, так как их может быть трудно рассуждать.

5
ответ дан 18 December 2019 в 09:50
поделиться

Если ItemCollection представляет собой (общий) список , вы можете использовать его метод ForEach . Это даст вам новую область действия на i:

ItemCollection.ForEach(
    i =>
    {
        Something s = new Something();
        s.EventX += delegate { ProcessItem(i); };
        SomethingCollection.Add(s);
    });

Или вы можете использовать любой другой подходящий Linq -метод, например Выберите :

var somethings = ItemCollection.Select(
        i =>
        {
            Something s = new Something();
            s.EventX += delegate { ProcessItem(i); };
            return s;
        });
foreach(Something s in somethings)
    SomethingCollection.Add(s);
1
ответ дан 18 December 2019 в 09:50
поделиться

Проблема, с которой вы столкнулись, связана с такой конструкцией языка, как замыкание . Вторая часть кода устраняет проблему.

0
ответ дан 18 December 2019 в 09:50
поделиться
foreach(Item i on ItemCollection)
{
   Something s = new Something(i);
   s.EventX += (sender, eventArgs) => { ProcessItem(eventArgs.Item);};
   SomethingCollection.Add(s);
}

не могли бы вы просто передать 'i' в свой класс 'Something' и использовать его в аргументах событий EventX

0
ответ дан 18 December 2019 в 09:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: