.NET Core自定义类能否实现类似控制器的构造函数自动依赖注入?
在自定义类中实现.NET Core DI的自动注入
嘿 Stefano,这个问题问得很到位!咱们一步步来拆解:
首先得明确:.NET Core的DI系统默认只会自动处理由容器负责创建的对象的构造函数依赖。也就是说,如果你是自己用new MyClass()手动实例化的类,DI容器根本不知道这个对象的存在,自然不会帮你填充构造函数参数。
不过要实现你想要的类似[FromDI]的效果,有几种可行的方案,咱们一个个说:
1. 最标准的做法:把自定义类注册到DI容器
这是.NET Core DI设计的核心用法,也是最推荐的方式。只要把MyClass注册到容器里,容器在创建它的实例时,会自动解析并填充它的构造函数依赖:
// 在Program.cs的服务配置中注册 services.AddScoped<MyClass>(); services.AddScoped<IInputType, InputTypeImplementation>(); // 先注册依赖的接口实现
之后,在需要使用MyClass的地方(比如控制器、其他已注册的服务),直接通过构造函数注入MyClass即可:
public class HomeController : Controller { private readonly MyClass _myClass; public HomeController(MyClass myClass) { _myClass = myClass; // 此时MyClass构造函数中的IInputType已经被DI自动填充好了 } }
2. 手动从容器获取依赖(适合特殊场景)
如果因为某些原因,你必须手动new MyClass(),那可以直接从DI容器中获取IInputType的实例,再传给构造函数。不过这种方式有点像“服务定位器”模式,一般不推荐(会让代码耦合度变高,不利于测试),但应急是可以的:
// 假设你能拿到IServiceProvider实例(比如在控制器里注入了IServiceProvider) var inputService = _serviceProvider.GetRequiredService<IInputType>(); var myClass = new MyClass(inputService);
3. 自定义属性标记的注入逻辑(模拟[FromDI])
如果你真的想实现类似[FromDI]的属性标记效果,也可以自己写一套解析逻辑。步骤如下:
第一步:定义标记属性
[AttributeUsage(AttributeTargets.Parameter)] public class FromDIAttribute : Attribute { }
第二步:写一个辅助方法来解析带标记的参数
这个方法会检查构造函数的参数,如果带有[FromDI]标记,就从DI容器中获取对应的实例;否则使用手动传入的参数或者默认值:
public static T CreateWithDI<T>(IServiceProvider serviceProvider, params object[] manualArgs) { // 找到参数最多的构造函数(模拟DI的默认行为) var targetConstructor = typeof(T).GetConstructors() .OrderByDescending(c => c.GetParameters().Length) .First(); var resolvedParams = targetConstructor.GetParameters() .Select(param => { // 如果参数带有FromDI标记,从容器解析 if (param.GetCustomAttribute<FromDIAttribute>() != null) { return serviceProvider.GetRequiredService(param.ParameterType); } // 否则优先使用手动传入的参数,没有的话用默认值 var manualArg = manualArgs.FirstOrDefault(arg => arg.GetType() == param.ParameterType); return manualArg ?? param.DefaultValue; }) .ToArray(); return (T)Activator.CreateInstance(typeof(T), resolvedParams); }
第三步:使用这个方法创建实例
// 假设你有IServiceProvider实例 var myClass = CreateWithDI<MyClass>(_serviceProvider); // 此时MyClass构造函数中带[FromDI]的IInputType参数会被自动填充
不过要注意:这种自定义方式需要自己维护解析逻辑,还可能带来生命周期管理的问题(比如容器创建的实例和你手动创建的实例生命周期不一致),所以除非真的有特殊需求,还是优先用第一种标准方案。
内容的提问来源于stack exchange,提问作者stefano m
相关产品推荐
相关产品推荐

