如何在ActionFilterAttribute中获取未知泛型参数的IFooService?
如何在ActionFilterAttribute中使用未指定泛型参数的IFooService
首先得明确一点:你没法直接不指定泛型参数就获取到注册的IFooService<int>并调用方法,因为你的DI容器里注册的是封闭泛型类型(IFooService<int>),而你尝试获取的是开放泛型类型(IFooService<>),这二者在DI容器里是完全不同的服务类型,所以直接调用GetService(typeof(IFooService<>))会返回null,这就是你报错的原因。
不过有几种方案可以解决你的问题,根据你的场景选择:
方案1:如果已知泛型参数类型(比如只有int)
如果你的业务场景中,IFooService<T>的泛型参数只有int这一种,那最简单的方式就是直接在过滤器中获取封闭泛型的服务:
public class FooActionFilter : ActionFilterAttribute { public override void OnActionExecuted(ActionExecutedContext context) { var fooService = context.HttpContext.RequestServices.GetService<IFooService<int>>(); if (fooService != null) { var foos = fooService.GetFoos(); // 处理获取到的foos } } }
方案2:定义非泛型基接口(推荐,更优雅)
如果你的IFooService<T>有多种泛型参数实现,或者不想硬编码泛型参数,可以给泛型接口加一个非泛型的基接口,通过非泛型接口来统一调用:
第一步:修改接口定义
// 新增非泛型基接口 public interface IFooService { // 定义非泛型的方法,返回值用object或IEnumerable<object> IEnumerable<object> GetFoos(); } // 让泛型接口继承非泛型接口 public interface IFooService<T> : IFooService { // 用new关键字覆盖基接口的方法 new List<T> GetFoos(); }
第二步:修改实现类,显式实现非泛型接口
public class FooService : IFooService<int> { public List<int> GetFoos() { // 执行相关逻辑 return new List<int> { 1, 2, 3 }; } // 显式实现非泛型接口的方法,将泛型结果转为object集合 IEnumerable<object> IFooService.GetFoos() { return GetFoos().Cast<object>(); } }
第三步:在过滤器中获取非泛型服务
public class FooActionFilter : ActionFilterAttribute { public override void OnActionExecuted(ActionExecutedContext context) { // 获取所有实现了IFooService的服务(不管泛型参数) var fooServices = context.HttpContext.RequestServices.GetServices<IFooService>(); foreach (var service in fooServices) { var foos = service.GetFoos(); // 处理foos,注意这里是IEnumerable<object>类型,需要根据业务转换 } } }
这种方式既保留了泛型接口的类型安全,又能在过滤器中统一处理不同泛型参数的服务。
方案3:通过反射动态调用(不推荐,性能差)
如果无法修改原有的接口和实现类,只能通过反射来获取服务并调用方法:
public class FooActionFilter : ActionFilterAttribute { public override void OnActionExecuted(ActionExecutedContext context) { // 获取所有注册的、实现了IFooService<>的服务 var allServices = context.HttpContext.RequestServices.GetServices<object>(); foreach (var service in allServices) { var serviceType = service.GetType(); // 检查当前服务是否实现了IFooService<>开放泛型接口 var isFooService = serviceType.GetInterfaces() .Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IFooService<>)); if (isFooService) { // 反射获取GetFoos方法并调用 var getFoosMethod = serviceType.GetMethod("GetFoos"); if (getFoosMethod != null) { var result = getFoosMethod.Invoke(service, null); // 处理result,这里result是List<T>类型,需要根据业务转换 } } } } }
这种方式灵活性高,但反射会带来性能开销,而且代码可读性差,除非万不得已不建议使用。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

