使用多个构造函数注册泛型类型

时间:2016-09-30 04:28:40

标签: c# dependency-injection ioc-container simple-injector cachemanager

我正在尝试从Unity转移到Simple Injector,并且无法让Injection与Simple Injector一起使用。

工作Unity代码在

下面
var container = new UnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));

container.RegisterType(
    typeof(ICacheManager<>),
    new ContainerControlledLifetimeManager(),
    new InjectionFactory((c, targetType, name) =>
        CacheFactory.FromConfiguration(targetType.GenericTypeArguments[0], "myCache")));

我的尝试:

var registration = Lifestyle.Singleton.CreateRegistration(
    typeof(ICacheManager<>),
    typeof(BaseCacheManager<>), 
    container);

container.AddRegistration(
    serviceType: typeof(BaseCacheManager<>),
    registration: registration);

我收到以下错误

  

要使容器能够创建BaseCacheManager<Object>,它应该只有一个公共构造函数

1 个答案:

答案 0 :(得分:1)

有几种方法可以在Simple Injector中解决这个问题。

首先,总是让你的组件有一个构造函数,因为multiple constructors is an anti-pattern

但是,由于提供的类型来自外部库,因此您无法更改它。

您可以做的是从这个特定类型派生并创建一个只有一个构造函数的子类。此类型可以调用您感兴趣的基类的特定构造函数:

class MyBaseClassManager<T> : BaseCacheManager<T>
{
    public MyBaseClassManager([args]) : base([args]) { }
}

container.RegisterSingleton(typeof(ICacheManager<>), typeof(MyBaseCacheManager<>)):

但是,一般情况下,应该防止应用程序代码依赖于应用程序未定义的抽象,因为这是Dependency Inversion Principle(DIP)违规。 DIP指导我们定义应用程序定制的抽象。基于这种抽象,您可以定义一个将调用转发给外部组件的适配器。例如:

// In the application's core layer
public interface ICache<T>
{
}

// Adapter in the Composition Root
public sealed class CacheManagerCacheAdapter<T> : ICache<T>
{
    private static BaseCacheManager<T> manager = new BaseCacheManager<T>();

    // Implement ICache<T> methods
    public object GetByKey(object key)
    {
        // translate and forward to the external component
        return this.manager[key];
    }
}

// Registration
container.RegisterSingleton(typeof(ICache<>), typeof(CacheManagerCacheAdapter<>)):

如果您需要的已关闭类型的数量有限,您还可以明确注册每个已关闭的版本:

container.RegisterSingleton<ICacheManager<Foo>>(new BaseCacheManager<Foo>());    
container.RegisterSingleton<ICacheManager<Bar>>(new BaseCacheManager<Bar>());    
container.RegisterSingleton<ICacheManager<FooBar>>(new BaseCacheManager<FooBar>());    

另一个选项是覆盖构造函数解析行为,如here所述。你可以这样做

public class CacheManagerConstructorResolutionBehavior 
    : IConstructorResolutionBehavior {
    private readonly IConstructorResolutionBehavior org;
    public CacheManagerConstructorResolutionBehavior(IConstructorResolutionBehavior org) {
        this.org = org;
    }
    public ConstructorInfo GetConstructor(Type serviceType, Type implementationType) {
        if (implementationType.IsGenericType && 
            implementationType.GetGenericTypeDefinition() == typeof(BaseCacheManager<>)) {
            return implementationType.GetConstructors()
                .OrderByDescending(c => c.GetParameters().Length)
                .First();
        }
        return this.org.GetConstructor(serviceType, implementationType);
    }
}

var container = new Container();
container.Options.ConstructorResolutionBehavior =
    new CacheManagerConstructorResolutionBehavior(
        container.Options.ConstructorResolutionBehavior);

另一个选择是挂钩ResolveUnregisteredType` event,虽然我只是建议这是最后的手段。