为什么需要 Lambda 函数将值传递给@onclick 调用的方法?

时间:2021-05-30 06:40:01

标签: c# html blazor blazor-webassembly

我是 Blazor 的新手(以及一般的 Web 开发人员)。我一直跟着 Microsoft's Blazor web app Todo List tutorial,在完成上述教程后,我想更进一步,在每个列表元素旁边添加按钮以将它们从列表中删除。这是我编写的代码来实现:

@page "/todo"

<h1>Todo (@todos.Count(todo => !todo.IsDone))</h1>

<ul>
    @foreach (var todo in todos)
    {
        <li>
            <input type="checkbox" @bind="todo.IsDone" />
            <input @bind="todo.Title" />
            <button @onclick="RemoveTodo(todo)">Remove</button>
        </li>
    }
</ul>

<input placeholder="Something to do" @bind="newTodo" />
<button @onclick="AddTodo">Add todo</button>

@code {
    private List<TodoItem> todos = new();
    private string newTodo;
    
    private void AddTodo()
    {
        if (!string.IsNullOrWhiteSpace(newTodo))
        {
            todos.Add(new TodoItem { Title = newTodo });
            newTodo = string.Empty;
        }
    }
    
    private void RemoveTodo(TodoItem item)
    {
        if (item != null)
        {
            todos.Remove(item);
        }
    }
}

我以为我可以从 <button @onclick="AddTodo">Add todo</button> 复制语法来添加此按钮,但这会引入一个错误。正如我通过 this Stack Overflow answer 发现的那样,为了修复这个错误(并允许应用程序构建),我必须更改:

<button @onclick="RemoveTodo(todo)">Remove</button>

像这样包含一个 lambda 函数:

<button @onclick="() => RemoveTodo(todo)">Remove</button>

我知道此更改有效,因为我对其进行了测试,并且该应用的行为符合我的预期!但我想知道为什么这种变化有效。

我发现了这个 additional Stack Overflow question,其中选择的答案解释了为了将值传递给@onclick 以上述方式调用的方法,必须使用 lambda 表达式。答案是使用 @onclick 会导致编译器创建一个 EventCallback 对象来处理我提供给 @onclick 的代码。

然而,我仍然不明白为什么我的原始代码不起作用。我假设当一个值被传递给它正在执行的函数时,由 EventCallback 对象生成的委托无法正确执行。第二个问题表明通过 lambda 函数调用会产生一种不同类型的委托,它可以解析传递给函数的值。

我对正在发生的事情的理解接近真相吗?为什么我需要以这种方式在 lambda 函数内部封装函数,但仅在所述函数被传递值时才需要?

2 个答案:

答案 0 :(得分:2)

它是关于 C# 语法的。事件处理程序必须是委托(对方法的引用)。

显示错误的最短方式:

<button @onclick="AddTodo">Add todo</button>         // ok
<button @onclick="AddTodo()">Add todo</button>       // error
<button @onclick="() => AddTodo()">Add todo</button> // ok

因为,在普通的 C# 中:

delegate x = AddTodo;    // ok, a methodname w/o () means "address off"
delegate x = AddTodo();  // error, void is not a delegate
delegate x = () => AddTodo();  // ok, a lambda is a delegate

我们通常更喜欢第一个较短的版本。但是一旦你有一个论点,你就需要长格式。

答案 1 :(得分:1)

如果您将鼠标悬停在任何控件中的 @onclick(或其他 @events)上,您将获得有关默认期望的函数的信息:字符串或委托值,如果是委托,则应该是 MouseEventArgs 类型(在本例中)

我不会推测他们为什么以这种或另一种方式做事,但文档显示了在 Blazor 中处理事件的各种方法的示例:

https://docs.microsoft.com/en-us/aspnet/core/blazor/components/event-handling?view=aspnetcore-5.0

IMO,官方文档通常非常好。我通常用谷歌搜索“MSDN BLAZOR ____”来找到我想要的。

相关问题