Blazor组件为何可传Void方法却无法传递Action?
问题描述
我开发了一个基于MudBlazor的Blazor对话框组件SimpleDialogComponent,组件代码如下:
<MudDialog> <DialogContent> <MudText>@ContentText</MudText> </DialogContent> <DialogActions> <MudButton OnClick="Cancel">@CancelButtonText</MudButton> <MudButton Color="@Color" Variant="Variant.Filled" OnClick="@InvokeOkAction">@ButtonText</MudButton> </DialogActions> </MudDialog> @code { [CascadingParameter] MudDialogInstance? MudDialog { get; set; } [Parameter] public string? ContentText { get; set; } [Parameter] public string? ButtonText { get; set; } [Parameter] public string? CancelButtonText { get; set; } = "Anuluj"; [Parameter] public Color Color { get; set; } [Parameter] public Action? OkAction { get; set; } private void InvokeOkAction() { OkAction?.Invoke(); MudDialog?.Close(DialogResult.Ok(true)); } void Cancel() => MudDialog?.Cancel(); }
调用该组件的代码如下:
private void SaveAsProd() { var parameters = new DialogParameters(); parameters.Add("ContentText", "Do you really want to delete these records?"); parameters.Add("ButtonText", "Delete"); parameters.Add("OkAction", okaction!); var options = new DialogOptions() { CloseButton = true, MaxWidth = MaxWidth.ExtraSmall }; DialogService.Show<SimpleDialogComponent>("????", parameters, options); } private void okaction() { Console.WriteLine("asd");} private Action okaction2(){ return ()=> Console.WriteLine("asd");}
传递无返回值的okaction方法时可正常运行,但传递okaction2返回的Action对象或Lambda表达式时,抛出如下异常:
Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100] Unhandled exception rendering component: Unable to set property 'OkAction' on object of type 'xx.Client.Components.SimpleDialogComponent'. The error was: Specified cast is not valid. System.InvalidOperationException: Unable to set property 'OkAction' on object of type 'xx.Client.Components.SimpleDialogComponent'. The error was: Specified cast is not valid. ---> System.InvalidCastException: Specified cast is not valid.
请问这是什么原因?为何无法传递Action?使用Lambda表达式也会出现相同错误。
原因与解决方法
核心原因
MudBlazor的DialogParameters在处理委托类型参数时,对直接的方法组(如okaction)兼容性较好,但当传递匿名委托(Lambda)或动态生成的Action实例时,编译器会生成特定的匿名委托类型,而非直接的System.Action,导致类型转换失败。另外Blazor组件参数绑定系统对这类动态委托的解析支持有限。
解决方法
方法1:改用Func<Task>替代Action
将组件中的同步委托改为异步委托类型,适配Blazor的参数传递机制:
@code { // 替换原有Action参数 [Parameter] public Func<Task>? OkAction { get; set; } private async Task InvokeOkAction() { if (OkAction != null) { await OkAction(); } MudDialog?.Close(DialogResult.Ok(true)); } }
调用时,所有形式的委托都能正常传递:
// 传递Lambda parameters.Add("OkAction", () => { Console.WriteLine("asd"); return Task.CompletedTask; }); // 传递okaction2返回的委托 parameters.Add("OkAction", okaction2()); // 原方法组调整为异步 private async Task okaction() { Console.WriteLine("asd");} private Func<Task> okaction2(){ return ()=> { Console.WriteLine("asd"); return Task.CompletedTask; };}
方法2:通过DialogResult触发回调
绕过组件参数传递委托,改为在对话框关闭后统一处理回调逻辑:
private async void SaveAsProd() { var parameters = new DialogParameters(); parameters.Add("ContentText", "Do you really want to delete these records?"); parameters.Add("ButtonText", "Delete"); var options = new DialogOptions() { CloseButton = true, MaxWidth = MaxWidth.ExtraSmall }; var dialog = DialogService.Show<SimpleDialogComponent>("Confirm", parameters, options); var result = await dialog.Result; if (!result.Canceled) { // 执行原OkAction逻辑 Console.WriteLine("asd"); // 或调用动态生成的委托 okaction2().Invoke(); } }
此时组件可移除OkAction参数,仅保留对话框关闭逻辑即可。
内容的提问来源于stack exchange,提问作者Dorian
相关产品推荐
相关产品推荐

