依赖注入到 {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 并将其注入属性。