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を増やしているので、何かを見逃している可能性があります。
これは実際には非常に簡単です。
container.RegisterType<IEnumerable<IParserBuilder>, IParserBuilder[]>();
Unity 配列をネイティブに理解するなので、列挙型を同じ型の配列にマップする必要があります。
@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>()
_
IEnumerableを一般的にサポートする場合は、次の行を追加できます。
_container.RegisterType(typeof(IEnumerable<>), new InjectionFactory((IUnityContainer container, Type type, string name) => container.ResolveAll(type.GetGenericArguments().Single())));
これは彼のジェネリック版です
container.RegisterType<IEnumerable<IParserBuilder>, IParserBuilder[]>();
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)。
ザ・
container.RegisterType<IEnumerable<IParserBuilder>, IParserBuilder[]>();
私のために働いたのは、IParserBuilderタイプをコンテナーに登録するときは一意の名前が必要であり、そうでない場合は常に空の配列になることだけを覚えておいてください。だから使用する
container.RegisterType<IParserBuilder, RealParserBuilder>("UniqueName");
私はそうしました
container.RegisterTypes(
AllClasses.FromLoadedAssemblies().
Where(type => typeof(IParserBuilder).IsAssignableFrom(type)),
WithMappings.FromAllInterfaces,
WithName.TypeName,
WithLifetime.Transient);
container.RegisterType<IEnumerable<IParserBuilder>, IParserBuilder[]>();
これはIParserBuilder
を実装するすべてのものを登録するため、新しいコードを追加するときに、ビルダーのリストに表示するために他のコードを追加する必要はありません。
2010年5月の時点で、そのためのネイティブサポートがあります。それをチェックしてください ここ 。
あなたはこのようにすることができます:
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")
)
));