问题
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).
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(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.
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?
回答1:
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);
}
UPDATE:
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:
- 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.
This would look like this:
// 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:
- Ignoring the registration by catching the exception thrown from
RegisterSingle. - Override an existing registration by setting
container.Options.AllowOverridingRegistrations = truebefore callingRegisterSingle(disabling it afterwards would be safest).
来源:https://stackoverflow.com/questions/13682333/multiple-registerall-registrations-using-the-same-set-of-singletons-with-simplei