依赖注入到 {get;设置;} 属性
Dependency Injection Into {get; set;} Property
我想知道如何设置依赖注入以将依赖项注入具有 public getter 和 setter ({get; set}) 的属性。
所以,一个例子是:
namespace Dexter.Services {
public class CommandHandlerService : InitializableModule {
public CommandService CommandService { get; set; }
}
}
使用以下依赖注入器:
namespace Dexter {
public static class InitializeDependencies {
public static async Task Main() {
ServiceCollection ServiceCollection = new();
CommandService CommandService = new();
ServiceCollection.AddSingleton(CommandService);
Assembly.GetExecutingAssembly().GetTypes()
.Where(Type => Type.IsSubclassOf(typeof(InitializableModule)) && !Type.IsAbstract)
.ToList().ForEach(
Type => ServiceCollection.TryAddSingleton(Type)
);
ServiceProvider = ServiceCollection.BuildServiceProvider();
// Initialization stuff.
}
}
}
在此示例中,我希望 CommandService 自动注入 属性。
我知道这是可能的,因为 Discord.NET 能够做到这一点,而且我愿意坚持使用相同的代码风格。
( Discord.NET: https://docs.stillu.cc/guides/commands/dependency-injection.html )
谢谢! <3
对于任何好奇的人,根据 Panagiotis 的建议,解决此问题的方法是创建您自己的依赖项注入。因此,我编写了一个小方法,循环遍历提供程序中的所有服务,并将 public 属性附加到它。它可能有错误!特别是关于范围内的服务,我没有写它来支持,但这对于希望获得类似结果的人来说应该是一个很好的起点!
public static object SetClassParameters(this object newClass, IServiceScope scope, IServiceProvider sp)
{
newClass.GetType().GetProperties().ToList().ForEach(property =>
{
if (property.PropertyType == typeof(IServiceProvider))
property.SetValue(newClass, sp);
else
{
object service = scope.ServiceProvider.GetService(property.PropertyType);
if (service != null)
{
property.SetValue(newClass, service);
}
}
});
return newClass;
}
您可以使用如下方法将依赖项注入 classes。例如,我希望将它们注入 classes 中,扩展了我制作的抽象“事件”class。这可以在下面看到:
using (var scope = serviceProvider.CreateScope()) {
GetEvents().ForEach(
type => serviceProvider.GetRequiredService(type).SetClassParameters(scope, serviceProvider)
);
}
其中 GetEvents()
是一个自反函数,returns 所有 class 扩展给定的抽象 class。
无需使用 Quickwire NuGet 包换出默认 DI 容器 (IServiceProvider
) 即可完成此操作。
只需使用 [RegisterService]
属性装饰您的服务,并将 [InjectService]
添加到 属性。不需要接口。
[RegisterService(ServiceLifetime.Singleton)]
public class CommandHandlerService {
[InjectService]
public CommandService CommandService { get; set; }
}
现在从你的主函数调用 ScanCurrentAssembly
:
public static async Task Main() {
ServiceCollection ServiceCollection = new();
ServiceCollection.ScanCurrentAssembly();
ServiceProvider = ServiceCollection.BuildServiceProvider();
// Initialization stuff.
}
在幕后,ScanCurrentAssembly
进行了所有必要的连接以解决依赖关系、实例化 class 并将其注入属性。
我想知道如何设置依赖注入以将依赖项注入具有 public getter 和 setter ({get; set}) 的属性。
所以,一个例子是:
namespace Dexter.Services {
public class CommandHandlerService : InitializableModule {
public CommandService CommandService { get; set; }
}
}
使用以下依赖注入器:
namespace Dexter {
public static class InitializeDependencies {
public static async Task Main() {
ServiceCollection ServiceCollection = new();
CommandService CommandService = new();
ServiceCollection.AddSingleton(CommandService);
Assembly.GetExecutingAssembly().GetTypes()
.Where(Type => Type.IsSubclassOf(typeof(InitializableModule)) && !Type.IsAbstract)
.ToList().ForEach(
Type => ServiceCollection.TryAddSingleton(Type)
);
ServiceProvider = ServiceCollection.BuildServiceProvider();
// Initialization stuff.
}
}
}
在此示例中,我希望 CommandService 自动注入 属性。
我知道这是可能的,因为 Discord.NET 能够做到这一点,而且我愿意坚持使用相同的代码风格。
( Discord.NET: https://docs.stillu.cc/guides/commands/dependency-injection.html )
谢谢! <3
对于任何好奇的人,根据 Panagiotis 的建议,解决此问题的方法是创建您自己的依赖项注入。因此,我编写了一个小方法,循环遍历提供程序中的所有服务,并将 public 属性附加到它。它可能有错误!特别是关于范围内的服务,我没有写它来支持,但这对于希望获得类似结果的人来说应该是一个很好的起点!
public static object SetClassParameters(this object newClass, IServiceScope scope, IServiceProvider sp)
{
newClass.GetType().GetProperties().ToList().ForEach(property =>
{
if (property.PropertyType == typeof(IServiceProvider))
property.SetValue(newClass, sp);
else
{
object service = scope.ServiceProvider.GetService(property.PropertyType);
if (service != null)
{
property.SetValue(newClass, service);
}
}
});
return newClass;
}
您可以使用如下方法将依赖项注入 classes。例如,我希望将它们注入 classes 中,扩展了我制作的抽象“事件”class。这可以在下面看到:
using (var scope = serviceProvider.CreateScope()) {
GetEvents().ForEach(
type => serviceProvider.GetRequiredService(type).SetClassParameters(scope, serviceProvider)
);
}
其中 GetEvents()
是一个自反函数,returns 所有 class 扩展给定的抽象 class。
无需使用 Quickwire NuGet 包换出默认 DI 容器 (IServiceProvider
) 即可完成此操作。
只需使用 [RegisterService]
属性装饰您的服务,并将 [InjectService]
添加到 属性。不需要接口。
[RegisterService(ServiceLifetime.Singleton)]
public class CommandHandlerService {
[InjectService]
public CommandService CommandService { get; set; }
}
现在从你的主函数调用 ScanCurrentAssembly
:
public static async Task Main() {
ServiceCollection ServiceCollection = new();
ServiceCollection.ScanCurrentAssembly();
ServiceProvider = ServiceCollection.BuildServiceProvider();
// Initialization stuff.
}
在幕后,ScanCurrentAssembly
进行了所有必要的连接以解决依赖关系、实例化 class 并将其注入属性。