如何从回调函数推断泛型参数类型?实现无显式类型的Subscribe调用
当然可以实现无需显式指定泛型参数的调用!
咱们先拆解下问题根源,再一步步给出解决方案:
为什么当前必须显式指定类型?
你的Subscribe<T, TResult>(Func<T, TResult> action)签名本身是支持类型推断的,但有两个场景会让编译器“卡壳”:
- 传入无返回值的方法组:比如
AddComment是void返回,它对应的是Action<T>而非Func<T, TResult>,编译器找不到匹配的TResult类型。 - 传入有返回值的方法组:方法组本身是“多态”的(比如如果方法有重载),编译器没有足够上下文确定它对应哪个
Func<T, TResult>委托,只能让你显式指定泛型参数。
解决方案:重载+lambda配合
1. 为无返回值方法添加Action<T>重载
先给Subscribe加一个专门处理无返回值逻辑的重载,这样编译器能直接推断出T类型:
// 新增无返回值重载 void Subscribe<T>(Action<T> action);
调用无返回值方法时就可以直接写:
_commandSubscription.Subscribe(Resolve<UpdateService>().AddComment);
2. 让有返回值方法自动推断类型
对于有返回值的方法,最简洁可靠的方式是用lambda表达式包裹方法调用——lambda的参数和返回值是明确的,编译器能轻松推断出T和TResult:
// 你的Service类示例 var service = new Service(); Queue.Subscribe(input => service.methodThatRequiresIntAndReturnsInt(input)); // UpdateService的CreateUpdate示例 var updateService = Resolve<UpdateService>(); _commandSubscription.Subscribe(cmd => updateService.CreateUpdate(cmd));
如果你不想用lambda,也可以显式把方法组转换成对应委托类型,但这种方式和显式指定泛型参数差不多,不如lambda简洁:
Queue.Subscribe((Func<int, int>)Service.methodThatRequiresIntAndReturnsInt);
完整示例代码
// 调整后的订阅类 public class CommandSubscription { // 处理有返回值的逻辑 public void Subscribe<T, TResult>(Func<T, TResult> action) { // 你的实现代码 } // 处理无返回值的逻辑 public void Subscribe<T>(Action<T> action) { // 可选:可以把Action包装成Func<T, object>复用上面的逻辑 Subscribe<T, object>(cmd => { action(cmd); return null; }); } } // 调用示例 var _commandSubscription = new CommandSubscription(); var updateService = Resolve<UpdateService>(); // 无返回值方法:自动推断T为AddCommentCommand _commandSubscription.Subscribe(updateService.AddComment); // 有返回值方法:lambda让编译器自动推断T=CreateUpdateCommand,TResult=bool _commandSubscription.Subscribe(cmd => updateService.CreateUpdate(cmd)); // Service类的调用示例 var service = new Service(); Queue.Subscribe(input => service.methodThatRequiresIntAndReturnsInt(input));
内容的提问来源于stack exchange,提问作者Vilmantas Petrusevicius
相关产品推荐
相关产品推荐

