0

Unity から Simple Injector に移行しようとしていますが、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 つだけ持つ必要があります。

4

1 に答える 1

1

Simple Injector でこれを解決する方法はいくつかあります。

まず第一に、複数のコンストラクターを持つことはアンチパターンであるため、コンポーネントには常に単一のコンストラクターを持たせてください。

ただし、提供されたタイプは外部ライブラリからのものであるため、変更することはできません。

代わりにできることは、この特定の型から派生させ、コンストラクターを 1 つだけ持つサブクラスを作成することです。この型は、関心のある基本クラスの特定のコンストラクターを呼び出すことができます。

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

もう 1 つのオプションは、ResolveUnregisteredType` イベントにフックすることですが、これは最後の手段としてのみお勧めします。

于 2016-09-30T05:57:47.600 に答える