0

NOTE

This question was asked in regards to the Blazor @bind feature. As it turns out @bind is just a delegate underneath (see the documentation), so it follows the same behaviour as delegates. See some of the other posts for a description of this.


I am building a table in which the number of rows depends on the number of elements in an array on a model. Each row should then bind to a value in the equivalent row of the array. Like this:

@for(int i = 0; i < round.PlayerScore.Length; i++)
{
    <tr>
        <th scope="row">@(i+1)</th>
        <td class="col-xs-1"><input id="name" @bind="round.PlayerScore[i]"
    </tr>
}

Problem is that this doesn't work. If I use i as index in the binding, I get an error. I need to first store i as seperate variable, for it to work, like such:

@for(int i = 0; i < round.PlayerScore.Length; i++)
{
    int local = i;
    <tr>
        <th scope="row">@(i+1)</th>
        <td class="col-xs-1"><input id="name" @bind="round.PlayerScore[local]"
    </tr>
}

The same thing is described in this github issue, but the conclusion is that it is the intended behaviour. One of the comments state that:

My understanding is that in C# for loops the same variable is reused (so all your lambda functions reference the length of your list).

In your workaround you are declaring a new variable each iteration which is the way C# requires lambdas to be written.

...but I don't really get what this means. When I print i+1 it correctly prints the numbers from 1 to 18 (if the array has length 18), so i seems to contain the correct value. Also, I cannot see it be anything but an int, since this is how it's initialised.

So why do I have to use a local placeholder (local) instead of the loop iterator (i)?

Jakob Busk Sørensen
  • 5,599
  • 7
  • 44
  • 96
  • `so i seems to contain the correct value` - it does. The problem is that the closure captures the variable itself, as in, the storage place, not its current contents. – GSerg Nov 15 '21 at 08:58
  • Does this answer your question? [Captured variable in a loop in C#](https://stackoverflow.com/q/271440/11683) – GSerg Nov 15 '21 at 08:58
  • Does this answer your question? [Captured Closure (Loop Variable) in C# 5.0](https://stackoverflow.com/q/16264289/11683) – GSerg Nov 15 '21 at 08:59
  • Maybe I just don't understand closures (or bind) well enough, but I don't get why it doesn't affect the printing of the variable (in the `` element). This comes out correct every time... – Jakob Busk Sørensen Nov 15 '21 at 09:00
  • @JakobBuskSørensen Because the printing happens inside the current loop iteration and nothing is retained, whereas the lambda captures the variable itself for later use. – GSerg Nov 15 '21 at 09:02
  • @GSerg fair enough, but in my case I don't use lamba's. I only use `@bind`, but perhaps this is a lambda underneath? – Jakob Busk Sørensen Nov 15 '21 at 09:03
  • 1
    Of course it is, what else could it be? The [documentation](https://learn.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-6.0) specifically spells out that `` is the same as ` InputValue = __e?.Value?.ToString())">`. – GSerg Nov 15 '21 at 09:06
  • Maybe I'm just stupid, but that doesn't seem completely obvious when you are new to Blazor :-). But once you know it, the behaviour makes sense. So thank you. I'll add that to the post and close it as a duplicate. – Jakob Busk Sørensen Nov 15 '21 at 09:12

0 Answers0