Вложенный цикл for в blazor – индексная переменная имеет максимальное значение?

Я хотел использовать вложенный цикл for в файле Razor и использовать индексы этих циклов for, чтобы определить, какое изображение показывать. Мой код выглядел так:

        @for (int i = 1; i < 6; i++)
        {
            <MudItem>
                @for (int j = 1; j < 6; j++)
                {  
                    stoel = GereserveerdeStoelen.Where(s => s.XPositionChair == i && s.YPositionChair == j).SingleOrDefault();
                    @if (stoel is null)
                    {
                        <MudImage Width = "40" Src = "images/chair.png" Alt = "chair" Class = "d-flex align-center justify-center py-8" />
                    }
                    else
                    {
                        <MudImage Width = "40" Src = "images/chair_not.png" Alt = "chair" Class = "d-flex align-center justify-center py-8" />
                    }
                }

            </MudItem>
        }

К сожалению, это, похоже, не сработало. Значение i, казалось, всегда было 6. Я не смог найти проблему именно для этой ситуации, но нашел аналогичную проблему с лямбда-выражениями, и решение для нее тоже сработало. Я присваиваю индекс локальной переменной, а затем использую эту локальную переменную.

Мой новый код выглядит так:

        @for (int i = 1; i < 6; i++)
        {
            int local = i;
            <MudItem>
                @for (int j = 1; j < 6; j++)
                {
                    stoel = GereserveerdeStoelen.Where(s => s.XPositionChair == local && s.YPositionChair == j).SingleOrDefault();
                    @if (stoel is null)
                    {
                        <MudImage Width = "40" Src = "images/chair.png" Alt = "chair" Class = "d-flex align-center justify-center py-8" />
                    }
                    else
                    {
                        <MudImage Width = "40" Src = "images/chair_not.png" Alt = "chair" Class = "d-flex align-center justify-center py-8" />
                    }
                }

            </MudItem>
        }

Однако я не совсем понимаю проблему и почему это решение работает. Может ли кто-нибудь дать объяснение?

почему бы не использовать отладчик, просмотреть код и посмотреть фактические значения i и j?

Uwe Keim 12.07.2024 16:16

@UweKeim Я сделал это, именно так я обнаружил, что значение i всегда было 6.

Tigris 12.07.2024 16:17

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

Bennyboy1973 12.07.2024 16:40
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
3
54
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема, с которой вы столкнулись, связана с тем, как компилятор C# фиксирует переменные цикла в замыканиях.

Это хорошо известная проблема при использовании переменных, определенных в цикле, во вложенных конструкциях (например, лямбда-выражениях или блоках кода Razor).

Когда вы используете переменную цикла внутри вложенной конструкции, переменная не просто копируется в эту конструкцию; вместо этого конструкция фиксирует ссылку на переменную цикла. Это означает, что все итерации цикла используют одну и ту же переменную, что приводит к неожиданному поведению.

В первом предоставленном вами фрагменте кода переменная i фиксируется блоком кода Razor, и поскольку блок кода Razor фактически создает замыкание, значение захваченной переменной во время выполнения будет последним значением, которое она имела в цикле ( в данном случае это 6).

Во втором фрагменте кода (тот, который вам помог) local — это новая переменная, которая содержит текущее значение i для каждой итерации. Это гарантирует, что каждая итерация внешнего цикла имеет собственное уникальное значение local, и, таким образом, вложенные конструкции фиксируют правильное значение.

Вы можете проверить Захват внешних переменных и области видимости переменных в лямбда-выражениях и другие разделы. Надеюсь, они дадут лучшее представление о том, что я пытаюсь донести.

Редактировать

Рассмотрим следующий упрощенный пример без синтаксиса Razor, но демонстрирующий тот же принцип:

var actions = new List<Action>();

for (int i = 0; i < 3; i++)
{
    for (int j = 0; j < 3; j++)
    {
        actions.Add(() => Console.WriteLine($"i: {i}, j: {j}"));
    }
}

// Execute actions
foreach (var action in actions)
{
    action();
}

вы могли бы подумать, что результат или результат будут чем-то вроде:

i: 0, j: 0
i: 0, j: 1
i: 0, j: 2
i: 1, j: 0
i: 1, j: 1
etc...

но фактический результат таков:

i: 3, j: 3
i: 3, j: 3
i: 3, j: 3
i: 3, j: 3
etc... you got the point

Таким образом, окончательным решением было бы захватить и i, и j с помощью локальных переменных, таких как int localI = i; и int localJ = j;. В конечном итоге вы получите ожидаемое «правильное» поведение.

Не могли бы вы рассказать, почему эта проблема возникает с самым внешним индексом цикла (i), но не с самым внутренним (j)? И почему эта проблема возникает в Blazor? Я понимаю, что лямбда-выражения оцениваются позже, но что насчет Blazor, позволяющего захватывать ссылку вместо фактического значения?

Tigris 12.07.2024 16:51

@Tigris Проблема с захватом переменной цикла возникает как для самого внешнего, так и для самого внутреннего индекса цикла. Однако эффект более очевиден (и важен) во внешнем цикле, когда задействованы вложенные циклы, поскольку переменная внешнего цикла используется совместно во многих итерациях внутреннего цикла. Я отредактирую свой ответ с примером позже

mrSoh 12.07.2024 16:55

Очень хорошо написано и объяснено. Хороший ответ.

Lex 15.07.2024 23:09

Другие вопросы по теме