簡體   English   中英

向多個構造函數注冊通用類型

[英]Registering generic type with multiple constructors

我正在嘗試從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>它應該只有一個公共構造函數

您可以通過多種方法在Simple Injector中解決此問題。

首先,始終讓您的組件具有單個構造函數,因為具有多個構造函數是一種反模式

但是,由於提供的類型來自外部庫,因此您無法更改它。

相反,您可以做的是從此特定類型派生並創建一個只有一個構造函數的子類。 這種類型可以調用您感興趣的基類的特定構造函數:

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

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

但是,通常,應避免讓應用程序代碼依賴於應用程序未定義的抽象,因為這是對依賴關系倒置原則 (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>());    

另一個選擇是重寫構造函數解析行為,如解釋在這里 你可以這樣做

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`事件,盡管我只建議這樣做。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM