web-dev-qa-db-ja.com

UnityでIEnumerable <T>を解決する

UnityはIEnumerable<T>を自動的に解決できますか?

このコンストラクターを持つクラスがあるとしましょう:

public CoalescingParserSelector(IEnumerable<IParserBuilder> parserBuilders)

コンテナ内の個々のIParserBuilderインスタンスを構成します。

container.RegisterType<IParserSelector, CoalescingParserSelector>();
container.RegisterType<IParserBuilder, HelpParserBuilder>();
container.RegisterType<IParserBuilder, SomeOtherParserBuilder>();

IEnumerable<IParserBuilder>のカスタム実装を実装せずにこれを機能させることはできますか?

var selector = container.Resolve<IParserSelector>();

これまでのところ、これを簡単な方法で表現することはできませんでしたが、まだUnityを増やしているので、何かを見逃している可能性があります。

38
Mark Seemann

これは実際には非常に簡単です。

container.RegisterType<IEnumerable<IParserBuilder>, IParserBuilder[]>();

Unity 配列をネイティブに理解するなので、列挙型を同じ型の配列にマップする必要があります。

63
Mark Seemann

@Metro Smurf:あなたの答えは私を正しい方向に導きました:Unityは_IEnumerable<T>_の依存関係を自動的に解決できません。

RegisterTypeメソッドはInjectionConstructorインスタンスをパラメーターとして受け取らないため、例をコンパイルできませんでした。

また、ResolveAllメソッドは、異なる名前で複数のタイプを登録した場合にのみ機能し、このメソッドはデフォルトの(名前のない)登録のインスタンスを返さないことにも注意してください。 (私はこの振る舞いに完全に同意しません)。

これは私のために働いたものです:

_container.RegisterType<IParserBuilder, HelpParserBuilder>("HelpParserBuilder");
container.RegisterType<IParserBuilder, SomeOtherParserBuilder>("SomeOtherParserBuilder");
container.RegisterType<IParserSelector, CoalescingParserSelector>();

container.Configure<InjectedMembers>().ConfigureInjectionFor<CoalescingParserSelector>(new InjectionConstructor(container.ResolveAll<IParserBuilder>()));
_

単一のインスタンスを解決するには、デフォルトの登録も追加する必要があります。そうしないと、Resolve<T>()の呼び出しが失敗します。

このコードは、単一の解決を有効にするためのデフォルトの登録を行います。

_container.RegisterType<IParserBuilder, HelpParserBuilder>();
IParserBuilder builder = container.Resolve<IParserBuilder>()
_
12
JCallico

IEnumerableを一般的にサポートする場合は、次の行を追加できます。

_container.RegisterType(typeof(IEnumerable<>), new InjectionFactory((IUnityContainer container, Type type, string name) => container.ResolveAll(type.GetGenericArguments().Single())));

これは彼のジェネリック版です

container.RegisterType<IEnumerable<IParserBuilder>, IParserBuilder[]>();
8
huer12

ResolveAll メソッドを使用し、明示的な InjectionConstructor オブジェクトを使用する必要があると思います。

container.RegisterType<IParserBuilder, HelpParserBuilder>();
container.RegisterType<IParserBuilder, SomeOtherParserBuilder>();

var injectedBuilders = new InjectionConstructor(container.ResolveAll<IParserBuilder>());
container.RegisterType<IParserSelector, CoalescingParserSelector>(injectedBuilders);

言い換えると、Unityが型のすべてのインスタンスを自動的に解決できず、 InjectionConstructor オブジェクトを-で明示的に宣言せずに、IEnumerableパラメーターを使用してクラスでコンストラクターインジェクションを使用できるとは思いません。 実行時間

確かに私はまだUnityも学んでいますが、これは私の経験です(YMMV)。

6
Metro Smurf

ザ・

container.RegisterType<IEnumerable<IParserBuilder>, IParserBuilder[]>();

私のために働いたのは、IParserBuilderタイプをコンテナーに登録するときは一意の名前が必要であり、そうでない場合は常に空の配列になることだけを覚えておいてください。だから使用する

container.RegisterType<IParserBuilder, RealParserBuilder>("UniqueName");
5
Gertjan

私はそうしました

        container.RegisterTypes(
            AllClasses.FromLoadedAssemblies().
                Where(type => typeof(IParserBuilder).IsAssignableFrom(type)),
            WithMappings.FromAllInterfaces,
            WithName.TypeName,
            WithLifetime.Transient);

        container.RegisterType<IEnumerable<IParserBuilder>, IParserBuilder[]>();

これはIParserBuilderを実装するすべてのものを登録するため、新しいコードを追加するときに、ビルダーのリストに表示するために他のコードを追加する必要はありません。

4
Loofer

2010年5月の時点で、そのためのネイティブサポートがあります。それをチェックしてください ここ

4
pwlodek

あなたはこのようにすることができます:

container.RegisterType<IParserBuilder, HelpParserBuilder>("HelpParser");
container.RegisterType<IParserBuilder, SomeOtherParserBuilder>("SomeOtherParser");

container.RegisterType<IParserSelector, CoalescingParserSelector>(
 new InjectionConstructor(
                    new ResolvedArrayParameter<IParserBuilder>(
                        new ResolvedParameter<IParserBuilder>("HelpParser"),
                        new ResolvedParameter<IParserBuilder>("SomeOtherParser")
                    )
));
0