web-dev-qa-db-ja.com

Autofacを使用してコンテナー自体を登録する

それ自体の中にコンテナを登録することに副作用があるのだろうかと思っていました

IContainer container;
ContainerBuilder builder = new ContainerBuilder();
container = builder.Build();
builder.RegisterInstance(container).As<IContainer>();

そしてそれをこのように使う

builder.RegisterType<IManagmentServiceImp>().As<ManagmentServiceImp>()
    .WithParameter(new ResolvedParameter(
            (pi, ctx) => pi.ParameterType == typeof(IContainer) && pi.Name == "Container",
            (pi, ctx) => container
));

またはそれがうまくいくかどうか。

11
Scarnet

初期化する前にインスタンスを登録するため、コードは安全ではありません。

コンポーネント内のコンテナーにアクセスする必要がある場合(これは良い方法ではありません)、ILifetimeScopeメソッドを持つResolveに依存することができます。

public class ManagmentServiceImp 
{
    public ManagmentServiceImp(ILifetimeScope scope)
    {
    }
}

ILifetimeScopeAutofac内に自動的に登録され、登録を追加する必要はありません。

詳細については、Autofacドキュメントの スコープとライフタイムの制御 を参照してください。

ちなみに、IoCコンテナーに依存することはお勧めできません。 Service Locator アンチパターンを使用しているようです。依存関係を遅延ロードするコンテナが必要な場合は、Func<T>またはLazy<T>で構成を使用できます

public class ManagmentServiceImp 
{
    public ManagmentServiceImp(Lazy<MyService> myService)
    {
        this._myService = myService; 
    }

    private readonly Lazy<MyService> _myService;
}

この場合、最初にアクセスしたときにMyServiceが作成されます。

詳細については、Autofacドキュメントの Implicit Relationship を参照してください。

27
Cyril Durand

この拡張メソッドを使用できます。

_public static void RegisterSelf(this ContainerBuilder builder)
{
    IContainer container = null;
    builder.Register(c => container).AsSelf();
    builder.RegisterBuildCallback(c => container = c);
}
_

次のように使用します:builder.RegisterSelf();

12
torvin

コンテナのインスタンスをbuilder.RegisterInstance()に提供する必要があるため、引数として渡す前に初期化する必要がありますが、現在は行っていません。ただし、コンテナービルダーを構築してAFTER登録(およびコンテナーの初期化)をビルドすると、クラスのコンテナーインスタンスを正常に解決できます。

これは、Dependency Injectionのデザインの匂いであることが最も確実であり、絶対にこれを行うべきではないことに注意してください。コンテナ/カーネルは、オブジェクトグラフの最上位にのみ存在する必要があります。コンテナーの注入を開始すると、ほぼ確実にService Locator Anti-Patternに向かっています。

void Main()
{
    IContainer container = new ContainerBuilder().Build();
    ContainerBuilder builder = new ContainerBuilder();

    builder.RegisterInstance(container).As<IContainer>();

    builder.RegisterType<ManagementServiceImp>().As<IManagmentServiceImp>()
       .WithParameter(new ResolvedParameter(
            (pi, ctx) => pi.ParameterType == typeof(IContainer) && pi.Name == "Container",
            (pi, ctx) => container
    ));

    container = builder.Build();
    var instance = container.Resolve<IManagmentServiceImp>();
}

public class ManagementServiceImp : IManagmentServiceImp 
{ 
    private IContainer _container;

    public ManagementServiceImp(IContainer Container)
    {
        _container = Container;
        _container.Dump();
    }
}

public interface IManagmentServiceImp { }
2
David L