使用同一套单身人士SimpleInjector的多个RegisterAll注册多个、单身、人士、SimpleInjector

2023-09-03 21:57:43 作者:不喊痛、不一定没感觉

我要建一个插件系统,电子商务项目,简单的注射器。我使用 RegisterAll 注册所有实施的 IPaymentProvider A IResourceRegistrar (和在fure以上)。

I'm building a plugin system for an e-commerce project with Simple Injector. I'm using RegisterAll to register all implementation of a IPaymentProvider and of a IResourceRegistrar (and in the fure more).

不过,这将创建一个新的实例每次。 这里是它建议使用 RegisterSingle 每种类型。但如何做到这一点在这种情况下?

But this creates a new instance each time. Here is it suggested to use RegisterSingle on each type. But how to achieve this in this case?

private static void RegisterMultipleUnderOneInterface(
    Container container, string name)
{
    IEnumerable<Type> pluginRegistrations =
        from dll in finder.Assemblies
        from type in dll.GetExportedTypes()
        where type.GetInterfaces().Any(i => i.Name == name)
        where !type.IsAbstract
        where !type.IsGenericTypeDefinition
        select type;

    if (pluginRegistrations.Any())
    {
        var @interface =
            pluginRegistrations.ElementAt(0).GetInterfaces()
            .First(i => i.Name == name);

        foreach (Type type in pluginRegistrations)
        {
            // HERE: register the type single somehow. 
        }

        container.RegisterAll(@interface, pluginRegistrations);
    }
} 

container.RegisterSingle(类型)不工作,从相同的接口固有的类型( IPaymentProvider IResourceRegistrar )。该 IPaymentProvider 实现类有构造不带参数的 IResourceRegistrar 用参数。

container.RegisterSingle(type) does not work, as the types inherent from the same interface (IPaymentProvider or IResourceRegistrar). The IPaymentProvider implementing classes have constructors without parameters, the IResourceRegistrar with parameters.

我不想做这样的事情,它,而违背了一个IoC容器的目的

I don't want to do something like this, it rather defeats the purpose of a IoC container

var constructor = type.GetConstructors()[0];

switch (name)
{
    case "IResourceRegistrar":
        container.RegisterSingle(type, () =>
        {
            return constructor.Invoke(new object[
            {
                container.GetInstance<ILanguageService>()});
            });
        break;
    case "IPaymentProvider":
    default:
        container.RegisterSingle(type, () =>
        {
            return constructor.Invoke(new object[] { });
        });
        break;
}

如何在不丑交换机注册这些作为单身?

How to register these as singleton without the ugly switch?

推荐答案

也许我误解,但RegisterSingle应该工作。你应该能够做到这一点:

Perhaps I misunderstand, but RegisterSingle should work. You should be able to do this:

var types = ...

container.RegisterAll<IInterface>(types);

foreach (var type in types)
{
    container.RegisterSingle(type, type);
}

更新:

所以,你正在尝试做的是自动配置如下:

So what you are trying to do is to automate the following configuration:

// A, B, C and D implement both I1 and I2.
container.RegisterSingle<A>();
container.RegisterSingle<B>();
container.RegisterSingle<C>();
container.RegisterSingle<D>();

container.RegisterAll<I1>(typeof(A), typeof(B), typeof(C), typeof(D));
container.RegisterAll<I2>(typeof(A), typeof(B), typeof(C), typeof(D));

这通常是自动执行此方式。所以,做四个步骤:

This would typically be the way to automate this. So do four steps:

找到所有类型的注册。 在注册类型中作为单。 在注册类型为集合列表 I1 。 在注册类型为集合列表 I2 。 Find all types to register. Register the found types as singleton. Register the list of types as collection for I1. Register the list of types as collection for I2.

这是这样的:

// using SimpleInjector.Extensions;

Type[] singletons = FindAllTypesToRegister();

foreach (Type type in singletons)
{
    container.RegisterSingle(type, type);
}

container.RegisterAll(typeof(I1), singletons);
container.RegisterAll(typeof(I2), singletons);

不过,因为你正试图分成两个步骤,创建一个可以处理每一步都有一个通用的方法,你将有当一个具体的单式已经注册忽略。您可以通过做到这一点:

However, since you are trying to split this into two steps and create one generic method that can handle each step, you will have to ignore when a concrete singleton type has already been registered. You can either do this by:

将捕获异常,从 RegisterSingle 抛出忽略登记。 通过设置覆盖现有注册 container.Options.AllowOverridingRegistrations = TRUE 之前调用 RegisterSingle (之后禁用它会是最安全的)。 Ignoring the registration by catching the exception thrown from RegisterSingle. Override an existing registration by setting container.Options.AllowOverridingRegistrations = true before calling RegisterSingle (disabling it afterwards would be safest).