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
相关产品推荐
相关产品推荐

