16

コンポーネントを条件付きで他のコンポーネントの状態に登録することは可能ですか? 何かのようなもの:

ContainerBuilder.RegisterConditionally<T>(
  Func<IComponentContext, bool>, 
  Func<IComponentContext, T>);

autofac の V2 より前ではRegister().OnlyIf()、私が探しているものと思われる " " 構造を使用できることがわかりました。このような機能で、デフォルトの登録を条件付きでオーバーライドしたいと考えています。

class CommonRegistrations
{
  public virtual void Register(ContainderBuilder builder)
  {
    builder.Register(ctx => LoadSettings()).As<ISettings>().SingleInstance();
    builder.RegisterType<DefaultFoo>().As<IFoo>();
  }
}

class SpecificRegistrations : CommonRegistrations
{
  public virtual void Register(ContainerBuilder builder)
  {
    base.Register(builder);
    builder.ConditionalyRegister(
      ctx => ctx.Resolve<ISettings>().ReallyUseSpecificFoo, 
      ctx => new SpecificFoo()).As<IFoo>();
  }
}

...

var builder = new ContainerBuilder();
var registrations = new SpecificRegistrations();
registrations.Register(builder);
var container = builder.Build();
IFoo foo = container.Resolve<IFoo>();

foo は、 のインスタンスまたは のインスタンスのISettings.ReallyUseSpecificFooいずれかに従います。DefaultFooSpecificFoo

ありがとうございました。

4

1 に答える 1

24

コンテナーの内容に基づいて、コンテナー レベルで条件付き登録を実行する方法はありません。問題は、コンテナに何が登録されるかを判断するために、コンテナ内の何かを解決する必要があることです。これは、最初にその物を登録するかどうかに技術的に影響を与える可能性があります。ニワトリと卵の循環依存問題。

ただし、ネストされたライフタイム スコープに条件付きで登録することはできます。ほとんどの統合ポイント (ASP.NET など) は、ネストされた有効期間スコープ (HTTP-request-length 有効期間スコープなど) から解決されます。ネストされたライフタイム スコープにオンザフライで登録でき、問題が解決する可能性があります。

var builder = new ContainerBuilder();
builder.Register(ctx => LoadSettings()).As<ISettings>().SingleInstance();
builder.RegisterType<DefaultFoo>().As<IFoo>();
var container = builder.Build();

var settings = container.Resolve<ISettings>();
using(var scope =
  container.BeginLifetimeScope(b => {
    if(settings.ReallyUseSpecificFoo)
    {
      b.RegisterType<SpecificFoo>().As<IFoo>();
    }
  })
{
  // Resolve things from the nested lifetime scope - it will
  // use the overrides. This will get the SpecificFoo if the
  // configuration setting is true.
  var foo = scope.Resolve<IFoo>();
}

あなたが持っている別のオプションは、登録をラムダにすることです。登録自体がより複雑になる可能性がありますが、検討できるオプションです。

var builder = new ContainerBuilder();
builder.Register(ctx => {
    var settings = ctx.Resolve<ISettings>();
    if(settings.ReallyUseSpecificFoo)
    {
      return new SpecificFoo();
    }
    return new DefaultFoo();
  }).As<IFoo>();

手作業による構築が魅力的でない場合は、Autofac を使用することもできます。

var builder = new ContainerBuilder();
// Register the IFoo types - but NOT "As<IFoo>"
builder.RegisterType<DefaultFoo>();
builder.RegisterType<SpecificFoo>();
// In the lambda use Resolve<T> to get the instances.
builder.Register(ctx => {
    var settings = ctx.Resolve<ISettings>();
    if(settings.ReallyUseSpecificFoo)
    {
      return ctx.Resolve<SpecificFoo>();
    }
    return ctx.Resolve<DefaultFoo>();
  }).As<IFoo>();

さらに別のオプションは、ビルド後に既存のコンテナーを更新することです。この場合、コンテナを実際に構築して使用し、事後に登録を変更することで、ニワトリ/タマゴのシナリオを回避します。

var builder = new ContainerBuilder();
builder.Register(ctx => LoadSettings()).As<ISettings>().SingleInstance();
builder.RegisterType<DefaultFoo>().As<IFoo>();
var container = builder.Build();

var settings = container.Resolve<ISettings>();
if(settings.ReallyUseSpecificFoo)
{
  var updater = new ContainerBuilder();
  updater.RegisterType<SpecificFoo>().As<IFoo>();
  updater.Update(container);
}

最後に、XML 構成を検討してください。登録が何らかの構成設定に依存していることを考えると、Autofac の XML 構成サポートの使用を検討することができます。そうすれば、ビルドされていないコンテナーから何かを解決して条件付きで何かを登録しようとする代わりに、XML 構成を使用して登録する正しいものを指定し、最初に正しいものを登録することができます。

于 2013-09-24T20:32:26.457 に答える