2012-06-07 11 views
8

ninjectを使用して、特定のジェネリック型のすべてのインスタンスをクラスに注入できます。たとえば、私はと同様の形式のカスタム抽出の束がありますNinject ninjectを持つジェネリック型のすべてのインスタンスの注入

public interface IExtract<TEntity> 
{ 
    TEntity ExtractFrom(MyBulkExportedEntity exportedEntity); 
} 

を、私は複数のバインディングをninject使用してこのファイルを処理するための責任のクラスにこれらの抽出のすべてのインスタンスを注入します。誰もがより良い方法を知っている場合

は過去に

public class ProcessDataExtract 
{ 
    /*This isn't valid c# but demonstrates the intent of what i would like to do*/ 
    public ProcessDataExtract(IEnumerable<IExtract<>> allExtractors) 
    { 
    } 

    public void Process(MyBulkExportedEntity exportedEntity) 
    { 
     /*loop through all of the extractors and pull relevant data from the object*/ 
    } 
} 

すなわち、私は直接カーネルにアクセスする管理クラスを(IProvideExtractors)を有することにより、これを行っているが、私はこの方法を好きではないと思っていましたこれをする。

public class ProcessDataExtract 
{ 
    public ProcessDataExtract<TExtract>(IEnumerable<IExtract<TExtract>> allExtractors) 
    { 
    } 
    ...etc... 
} 

そしてアウトリスト:ninject複数で、私は、その後のすべてのインスタンスがkernel.GetAll(typeof(IExtract<>))

+1

は、それが必要である:GenericArgumentBindingGeneratorとしてdefindある場合は

MyEntity : BaseEntity YourEntity : BaseEntity 

あなたは

Kernel.Bind(x => x.FromThisAssembly().SelectAllClasses() .InheritedFrom<BaseEntity>() .BindWith(new GenericArgumentBindingGenerator(typeof(IExtract<>)))); 

を次のように条約を指定することができます

Bind<IExtract>().To<ExtractImpl<MyEntity>>(); Bind<IExtract>().To<ExtractImpl<YourEntity>>(); 

'IExtractのために'は一般的ですか?もしそうでなければ、私は非一般的な 'IExtract'を作成し、' IExtract 'は' IExtract'から継承します。そして、あなたの 'ProcessDataExtract'コンストラクタに適切な登録があれば、' IEnumerable allExtractors'に従います。 – nemesv

答えて

4

でこれを行う方法がイマイチということのようです関連:私は、条約拡張を使用して、すべてのバインディングを個別に指定するつもりはありませんでした。

最初に:List<IExtract>を注入し、IExtract<T> : IExtractを継承する必要があります。 これは、C#では、異なるジェネリックを含むコレクションの型を指定できないという事実によるものです。あなたがあなたの質問に書いたように、それは無効な構文です - この答え以外の理由があります。

後でIExtractの要素をリストから引き出し、リフレクションを使用してジェネリック型のパラメタを取得して戻すことができます。それとも、あなたが探しているものを抽出するために知っていれば:

public IExtract<T> GetExtractor<T>() { 
    return (IExtract<T>)Extractors.Find(e => e is ExtractImpl<T>); 
} 

を今あなたがIExtract`にバインドされたいくつかのTをしたいそのためのクラスの束を持っているかもしれません。 `Process`メソッド内

public class GenericArgumentBindingGenerator : IBindingGenerator 
{ 
    private readonly Type m_Generic; 

    public GenericArgumentBindingGenerator(Type generic) 
    { 
     if (!generic.IsGenericTypeDefinition) 
     { 
      throw new ArgumentException("given type must be a generic type definition.", "generic"); 
     } 
     m_Generic = generic; 
    } 

    public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot) 
    { 
     if (type == null) 
      throw new ArgumentNullException("type"); 
     if (bindingRoot == null) 
      throw new ArgumentNullException("bindingRoot"); 
     if (type.IsAbstract || type.IsInterface) 
     { 
      return Enumerable.Empty<IBindingWhenInNamedWithOrOnSyntax<object>>(); 
     } 

     var bindings = new List<IBindingWhenInNamedWithOrOnSyntax<object>>(); 
     IBindingWhenInNamedWithOrOnSyntax<object> binding = bindingRoot 
      .Bind(typeof(IExtract)) // you maybe want to pass typeof(IExtract) to constructor 
      .To(m_Generic.MakeGenericType(type)); 

     bindings.Add(binding); 

     return bindings; 
    } 
} 
+0

私はこのバインディングジェネレータが本当に好きですが、これはかなりクールだと思います。バインディングの点でこの問題を解決するには、非ジェネリックを拡張するのが正しいと思います。 –

+0

IEnvironmentConfigFileとは何ですか? –

+0

ああ、私は1つ見逃していた - 私のコードからそれを得た;)IEnvironmentConfigFileは私が推測するIExtractだろう。しかしGenericArgumentBindingGeneratorのコンストラクタに渡してジェネリックにする必要があります。上記のように 'Bind ().To >();をバインドしてください。 – Tarion

1

オプション

を使用することに興味を持っイム得ることができますバインディング私はあなたがこれを行うことができますかなり確信していますバインディングモジュールのバインドを

... 
Bind<IExtract<TEntity>>().To<SomeConcreteExtract>(); 
Bind<IExtract<TEntity>>().To<AnotherConcreteExtract>(); 
Bind<IExtract<TEntity>>().To<YetAnotherConcreteExtract>(); 
... 

Injectはコンストラクタにそれらを渡し、それらの束に依存することを宣言します。私はこれまで成功してきました。

オプションB許す

public interface IExtract 
{ 
    TEntity ExtractFrom<TEntity>(MyBulkExportedEntity exportedEntity); 
} 

から

変更

public interface IExtract<TEntity> 
{ 
    TEntity ExtractFrom(MyBulkExportedEntity exportedEntity); 
} 

 public ProcessDataExtract<TExtract>(IEnumerable<IExtract<TExtract>> allExtractors) 
    { 
    } 
    ...etc... 

がために:

public ProcessDataExtract(IEnumerable<IExtract> allExtractors) 
    { 
    } 
    ...etc... 

そしてNInjectバインディングは、あまりにも、調整することになります。

... 
Bind<IExtract>().To<SomeConcreteExtract>(); 
Bind<IExtract>().To<AnotherConcreteExtract>(); 
Bind<IExtract>().To<YetAnotherConcreteExtract>(); 
... 
+0

そう、ninjectには、バインディングのすべてのインスタンスを注入するコンセプトがあります。これは私が利用したいものです。上記の例で 'kernel.GetAll(typeof(IExtract <>))'を使ってninjectから直接行うことができます。これは、すべての抽出プログラムを含む 'IEnumerable 'を返します。私の問題はこれではありませんが、私の問題は、上記のコードが有効ではないので、私のコンストラクタでこれを指定する方法がわかりません。C# –

+0

構文を修正しました。しかし、あなたはただ一つのコンクリート「TExtract」だけで立ち往生します。非ジェネリックベースクラス(抽象的であるか否か)である必要があります。あるいは、 'IExtract'の型パラメータを' ExtractFrom'にプッシュすることができます。これは、 'ProcessDataExtract'から均等性を取り除くことになります。私は私の答えに何を意味するかを追加します。 – bluevector

+0

私は 'typeof(IExtract ).IsAssignableFrom(tyepof(IExtract ))'を見ていないので、 'Enumerable > allExtractors'を使用することができたと言います。https: //compilify.net/1tj –

2

これに対する答えは、私が何かを探していたninject

+0

[Inject Array of Ninject](http://stackoverflow.com/questions/3102940/inject-array-of-interfaces-in-ninject)にはいくつかの回避策があります。 – ladenedge

関連する問題