简体   繁体   中英

Registering generic type with multiple constructors

I am trying to move from Unity to Simple Injector and having trouble getting the Injection to work with Simple Injector.

Working Unity code is below

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")));

My Attempts:

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

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

I am getting the following error

For the container to be able to create BaseCacheManager<Object> it should have only one public constructor

There are several ways you can solve this in Simple Injector.

First of all, always let your components have a single constructor, since having multiple constructors is an anti-pattern .

Since however the supplied type is from an external library, it is impossible for you to change it.

What you can do instead is derive from this particular type and create a sub class that only has one constructor. This type can call into the specific constructor of the base class you are interested in:

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

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

In general however, you should prevent having your application code depend on abstractions that are not defined by the application, since this is a Dependency Inversion Principle (DIP) violation. The DIP guides us into defining application-tailored abstractions. Based on such abstraction you can define an adapter that forwards the call to the external component. Example:

// 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<>)):

If the number of closed types you need is limited, you can also register every closed version explicitly:

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

Yet another option is to override Constructor Resolution Behavior, as explained here . You can do this

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);

Yet another option is to hook onto the ResolveUnregisteredType` event although I would only advise this as last resort.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM