web-dev-qa-db-ja.com

Autofacを使用したジェネリックインターフェイスの解決

次のコードが与えられた場合、autofacで正しいSomeInstanceを解決するにはどうすればよいですか?

public class BaseClass {}

public class SubClass1 : BaseClass {}

public class SubClass2 : BaseClass {}

public interface IGenericInterface<T> where T : BaseClass {}

public class SomeInstance1<T> : IGenericInterface<T> where T : SubClass1

public class SomeInstance2<T> : IGenericInterface<T> where T : SubClass2

サブクラスのジェネリックのタイプに基づいてSomeInstance1または2を選択したいと思います。

たとえば、サブクラスのコレクション(SubClass1、2 ....)があり、それらを反復処理しながら、適切なSomeInstanceクラスを選択したいとします。

31
DownChapel

Autofacはオープンジェネリックをサポートしています。コンパイル時にジェネリック型がわかっている場合は、次のコードを使用できます。

var builder = new ContainerBuilder();

builder.RegisterGeneric(typeof(SomeInstance1<>))
  .As(typeof(IGenericInterface<>));              

var container = builder.Build();

var instance1 = container.Resolve<IGenericInterface<SubClass1>>();

Assert.IsInstanceOfType(typeof(SomeInstance1<SubClass1>), instance1);

型パラメーターが実行時までわからない場合(型のコレクションを反復処理する場合はおそらくそうです)、MakeGenericTypeを使用して型を作成できます。

        var typeInRuntime = typeof (SubClass1);
        var instance1 = container.Resolve(typeof(IGenericInterface<>).MakeGenericType(typeInRuntime));
66
andrey.tsykunov

補正。コンテナからMakeGenericTypeを呼び出すことはできません。 Resolve呼び出しのパラメーターとして「TYPE」を使用してジェネリックスをインスタンス化する問題を解決しました。ビルダーが登録されています。

        builder.RegisterGeneric(typeof (FakeRepository<>)).As(typeof (IRepository<>)).OnActivating(e =>
        {
            var typeToLookup = e.Parameters.FirstOrDefault() as TypedParameter;
            if (typeToLookup != null)
            {
                var respositoryType = typeof (FakeRepository<>);
                Type[] typeArgs = {typeToLookup.Value.GetType()};
                var genericType = respositoryType.MakeGenericType(typeArgs);
                var genericRepository = Activator.CreateInstance(genericType);
                e.ReplaceInstance(genericRepository);
            }
        });

次に、このように解決が行われ、TypedParameterがResolveに渡されます。この場合、解決されたアイテムのリスト(IItem)があり、そのタイプのすべてのアイテムのリポジトリを作成します。

        var items = container.Resolve<IEnumerable<IItem<string>>>();
        foreach (var item in items)
        {
            var repository = container.Resolve(typeof (IRepository<DataItemBase>), new TypedParameter(item.GetType(), item));
            Assert.IsNotNull(repository);
        }

あなたの投稿に感謝します。このアップデートがお役に立てば幸いです。

4