You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Blazor使用dynamic调用EventCallback<T>时参数类型匹配异常问题

问题分析与解决方案

首先,你的问题确实和dynamic与EventCallback<T>的交互直接相关。EventCallback<T>是强类型的泛型结构,当你把它存为object再转成dynamic时,运行时解析InvokeAsync方法会出现歧义——它无法正确识别应该调用泛型版本的InvokeAsync(T),反而可能尝试匹配非泛型重载,最终触发类型不匹配异常。

解决办法一:用反射调用泛型InvokeAsync

既然你已经持有事件参数的类型(data.ArgumentType),可以通过反射精准找到对应的InvokeAsync方法并执行:

[JSInvokable]
public override async Task<object> Trigger(string eventName, string arg)
{
    EventData data = this.DelegateList[eventName];
    var eventArg = JsonConvert.DeserializeObject(arg, data.ArgumentType);
    
    // 获取EventCallback<T>的泛型InvokeAsync方法
    var invokeMethod = data.Handler.GetType()
        .GetMethod("InvokeAsync", new[] { data.ArgumentType });
    
    if (invokeMethod != null)
    {
        // 异步调用方法,确保等待操作完成
        await (Task)invokeMethod.Invoke(data.Handler, new[] { eventArg });
    }
    
    return eventArg;
}

注意这里把Trigger改成了async Task<object>,因为InvokeAsync返回异步任务,必须等待完成后再返回结果给JS,避免异步操作未执行完就提前返回。

解决办法二:在EventData中封装强类型委托

这个方案更高效,能彻底避免反射和dynamic的问题——在Set<T>方法里提前封装好强类型的调用逻辑:

public class EventData
{
    public Func<object, Task> InvokeHandler { get; set; }
    public Type ArgumentType { get; set; }

    public EventData Set<T>(EventCallback<T> action, Type type)
    {
        this.ArgumentType = type;
        // 封装成接受object参数的委托,内部自动完成类型转换
        this.InvokeHandler = async (arg) =>
        {
            var typedArg = (T)arg;
            await action.InvokeAsync(typedArg);
        };
        return this;
    }
}

接着修改base.cs和Comp.razor的Trigger方法:

// base.cs
internal virtual void SetEvent<T>(string name, EventCallback<T> eventCallback)
{
    if (this.DelegateList.ContainsKey(name))
    {
        this.DelegateList[name] = new EventData().Set<T>(eventCallback, typeof(T));
    }
    else
    {
        this.DelegateList.Add(name, new EventData().Set<T>(eventCallback, typeof(T)));
    }
}

// Comp.razor中的Trigger方法
[JSInvokable]
public override async Task<object> Trigger(string eventName, string arg)
{
    EventData data = this.DelegateList[eventName];
    var eventArg = JsonConvert.DeserializeObject(arg, data.ArgumentType);
    await data.InvokeHandler(eventArg);
    return eventArg;
}

这种方式完全绕开了dynamic和反射,通过提前封装的委托实现强类型调用,性能更优且不会出现类型推断问题。

额外注意事项

  • 务必确保JsonConvert.DeserializeObject能正确将字符串反序列化为目标类型,比如Nullable类型、嵌套复杂对象的反序列化需要提前做好配置。
  • 不要忽略异步操作的等待,否则JS端可能拿到未完成的异步结果,引发后续逻辑错误。

内容的提问来源于stack exchange,提问作者user3468621

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 06:22:57