"TextEntry.OnTextEdited needs an explicit-type block lambda"
Binding TextEntry.OnTextEdited (an Action<string>) in razor markup fails to compile in two different ways depending on how the lambda is written:
- Untyped lambda
OnTextEdited=@(t => _field = t)→CS8917: The delegate type could not be inferred(only in the in-editor compiler —dotnet buildmay not catch it). - Typed expression lambda
OnTextEdited=@((string t) => _field = t)→CS0029: Cannot implicitly convert type 'Func<string, string>' to 'Action<string>'— once the compiler has enough type info from the explicit param, it infers the expression-bodied assignment as returning the assigned value (aFunc), notvoid(anAction).
C#'s lambda type inference interacts with razor codegen in two stages:
-
Without an explicit parameter type, the razor compiler can't infer the delegate type at all — it doesn't know whether the target is
Action<string>,Func<string, string>, or something else. -
With an explicit parameter type but an expression body (
=> _field = t), the compiler resolves the assignment expression as having a return value. An assignment expression in C# evaluates to the assigned value, so the lambda is inferred asFunc<string, string>, which doesn't match theAction<string>delegate.
Use an explicit parameter type AND a block body so the assignment is a statement, not an expression:
<TextEntry OnTextEdited=@((string t) => { _field = t; }) />This is the established engine pattern — the engine's own CreateGameModal.razor uses the same explicit-type-plus-block shape:
(string x) => { Output.GameSettings[e.Name] = x; }Also note: TextEntry's Numeric bool property needs Numeric=@true (a real C# expression), not Numeric="true" (a markup string attribute). The latter fails with CS0029: Cannot implicitly convert type 'string' to 'bool' in the same codegen pass.
A block-bodied lambda { _field = t; } makes the assignment a statement — it has no return value, so the compiler correctly infers Action<string>. An expression-bodied lambda evaluates the expression for its result, and since _field = t evaluates to t (a string), the inferred type becomes Func<string, string>. The block body eliminates the ambiguity.