Darren Cook
Darren Cook

Reputation: 28928

Why do I get a variable scope error (CS0136) in a Html.HiddenFor?

Here is a stripped-down code snippet from a MVC3/Razor view file:

@foreach (var item in Model.Stuff.Items){
<tr>
  <td>@item.Title</td>
</tr>
<tr>
  <td>
    @using (Html.BeginForm()) {
        @item.Title
        @Html.HiddenFor(item => item.Title)
    }
  </td>
</tr>
}  @* End of Items foreach loop *@

The title shows on the first row. It also shows inside the form. But trying to use it in the HiddenFor I get error CS0136: A local variable named 'item' cannot be declared in this scope because it would give a different meaning to 'item', which is already used in a 'parent or current/child' scope to denote something else

I don't get why that would be the case; in item => item.Title the first "item" is effectively just a parameter name in an anonymous function, isn't it?

When I change it to: @Html.HiddenFor(s => s.Title) I get error CS1963, An expression tree may not contain a dynamic operation.

Background: the intention is to have two table rows per entry in Model.Stuff.Items, the first giving current information as static HTML, the second an edit form for it. (One or the other will be hidden at any time using javascript.) The form will submit to another action on this controller. All the forms submit to the same URL; the hidden values will identify which row is being updated.

Upvotes: 0

Views: 3661

Answers (3)

Darren Cook
Darren Cook

Reputation: 28928

For the CS1963 part of the problem, that is resolved by setting the @Model at the top of this partial view file, and then passing that as the 2nd parameter of HTML.Partial()

So, in my outer view, the Html.Partial line changed to look this like:

 @Html.Partial("partial.example",Model.Stuff.Items)

Then at the top of partial.examples.cshtml, I added:

@model IEnumberable<Type.Of.Items>

And the foreach line changed to be:

@foreach (var item in Model){

Finally, to get rid of the CS0136 error, as Yasser suggested:

@Html.HiddenFor(x => item.Title)

(And thanks to Jon for explaining why item => item.Title was not allowed.)

Upvotes: 1

Yasser Shaikh
Yasser Shaikh

Reputation: 47784

Use @Html.HiddenFor(x => item.Title)

@foreach (var item in Model.Stuff.Items){
<tr>
  <td>@item.Title</td>
</tr>
<tr>
  <td>
    @using (Html.BeginForm()) {
        @item.Title
        @Html.HiddenFor(x => item.Title)
    }
  </td>
</tr>
}

Upvotes: 2

Jon Skeet
Jon Skeet

Reputation: 1500595

I don't get why that would be the case; in item => item.Title the first "item" is effectively just a parameter name in an anonymous function, isn't it?

Yes, but it's introducing another variable with the same name into a scope which already includes a local variable of that name. You just can't do that. It would make it ambiguous when you use item within the lambda expression - it could mean the parameter, or it could mean the iteration variable.

Note that this has nothing to do with MVC or Razor. You get the same error with this code:

int x = 0;
Func<int, int> y = x => x;

From section 17.15.1 of the C# 5 spec:

The scope of the parameters of the anonymous function is the anonymous-function-body. (§3.7) Together with the parameter list (if given) the anonymous-method-body constitutes a declaration space (§3.3). It is thus a compile-time error for the name of a parameter of the anonymous function to match the name of a local variable, local constant or parameter whose scope includes the anonymous-method-expression or lambda-expression.

Upvotes: 3

Related Questions