Я хотел использовать вложенный цикл 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>
}
Однако я не совсем понимаю проблему и почему это решение работает. Может ли кто-нибудь дать объяснение?
@UweKeim Я сделал это, именно так я обнаружил, что значение i всегда было 6.
Я пытался воспроизвести эту проблему, но не смог. Со мной такое уже случалось, хотя я тоже не знаю точного механизма. Но я знаю, что ваше решение является рекомендуемым.
Проблема, с которой вы столкнулись, связана с тем, как компилятор 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 Проблема с захватом переменной цикла возникает как для самого внешнего, так и для самого внутреннего индекса цикла. Однако эффект более очевиден (и важен) во внешнем цикле, когда задействованы вложенные циклы, поскольку переменная внешнего цикла используется совместно во многих итерациях внутреннего цикла. Я отредактирую свой ответ с примером позже
Очень хорошо написано и объяснено. Хороший ответ.
почему бы не использовать отладчик, просмотреть код и посмотреть фактические значения
i
иj
?