为何ControllerActivatorProvider用Type.EmptyTypes创建激活器且支持带参控制器?
为什么
ActivatorUtilities.CreateFactory传入Type.EmptyTypes仍能创建带参数的控制器? 首先要明确ActivatorUtilities.CreateFactory第二个参数的核心含义:它不是指定目标类型的所有构造函数参数类型,而是指定你想要手动传入的参数类型列表。当传入Type.EmptyTypes时,相当于告诉工具:所有构造函数需要的参数,都从提供的IServiceProvider中自动解析获取,不需要手动传递任何参数。
具体执行逻辑
看你给出的源码片段:
public Func<ControllerContext, object> CreateActivator(ControllerActionDescriptor descriptor) { var controllerType = descriptor.ControllerTypeInfo?.AsType(); // ... var typeActivator = ActivatorUtilities.CreateFactory(controllerType, Type.EmptyTypes); return controllerContext => typeActivator(controllerContext.HttpContext.RequestServices, arguments: null); }
这里的typeActivator是一个工厂委托,调用它时传入了当前请求的DI容器(controllerContext.HttpContext.RequestServices),并且arguments设为null。
以你的HomeController为例:
public class HomeController: Controller { IUserRepository userRepo; public HomeController(IUserRepository userRepo) { this.userRepo = userRepo; } }
当工厂委托执行时,ActivatorUtilities会完成以下步骤:
- 分析
HomeController的构造函数,识别出它需要的参数类型IUserRepository; - 从传入的DI容器中查找已注册的
IUserRepository实例; - 用找到的实例作为参数,调用构造函数创建
HomeController对象。
何时需要传入非空参数类型列表?
只有当你想手动提供部分构造函数参数,剩下的由DI容器解析时,才需要在第二个参数里指定手动传入的参数类型。比如控制器构造函数是:
public HomeController(IUserRepository userRepo, string customParam) { this.userRepo = userRepo; this.customParam = customParam; }
此时如果想让userRepo由DI解析,customParam手动传入,就需要这样写:
var typeActivator = ActivatorUtilities.CreateFactory(controllerType, new[] { typeof(string) }); // 调用时手动传入customParam return controllerContext => typeActivator(controllerContext.HttpContext.RequestServices, new object[] { "手动传入的参数" });
回到ASP.NET Core的源码场景,控制器的所有依赖都应该由DI容器管理,因此不需要手动传入任何参数,使用Type.EmptyTypes完全合理。
内容的提问来源于stack exchange,提问作者user16276760
相关产品推荐
相关产品推荐

