2011-02-25 12 views
17

私はインターフェイスIExampleとクラスClassOneClassTwoClassThreeのセットを持っています。これらはすべて異なる名前空間で定義されています。クラスのいずれかを削除したり、開発の後の段階で新しい場所に新しいクラスを追加したりします。特定のインターフェイスを実装しているすべてのクラスをインスタンス化します

実行時にIExampleを実装するすべてのタイプを見つけて、をインスタンス化します。 (私は事前にIExampleを実装しているクラスはコンストラクタ引数を必要としないことを知っていますが、それをコードで指定する方法はわかりませんので、コンパイラではありません...)

これは可能?どうすればそれをやり遂げることができますか?

アップデート:私は今、提案のアプローチのいくつかを試してみたが、私は、「インターフェイスのインスタンスを作成することはできません。」ので、それらのすべて、ラインActivator.CreateInstance(type)に、私はSystem.MissingMethodExceptionを取得これは私のコードです:

var tasks = AppDomain.CurrentDomain.GetAssemblies() 
    .SelectMany(a => a.GetTypes()) 
    .Where(t => typeof(IBootstrapperTask).IsAssignableFrom(t)) 

    // This line is where it fails 
    .Select(t => Activator.CreateInstance(t) as IBootstrapperTask) 

    .ToArray(); 
new AutoMapperBootstrapper(tasks).Initialize(); 

私はすべての例外が表示されないas句がなければ、私はobject[]を与えている、と私は抜粋の最後の行のコンストラクタのためIBootstrapperTask[]を必要としています。私はそれをキャストする様々な方法を試したが、どれもうまくいかないようだ。

答えて

28

これは、リフレクションを行うことができます。例えば

var interfaceType = typeof(IExample); 
var all = AppDomain.CurrentDomain.GetAssemblies() 
    .SelectMany(x => x.GetTypes()) 
    .Where(x => interfaceType.IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract) 
    .Select(x => Activator.CreateInstance(x)); 

注:これは、現在のAppDomainにロードされたアセンブリからIExampleのインスタンスを作成します。これは、現在のプロセスにロードされているすべてのアセンブリとは異なる場合があります。しかし、多くのタイプのアプリケーションでは、これは同等です。

+4

もっと重要なことですが、すでにロードされているアセンブリのみが含まれます。 *参照されているがまだロードされていないものがあるかもしれません。個人的に私はそれをすべて明示的に保つことを好む:) –

0

リフレクションを使用してIExampleのタイプを取得してみてください。この例では、現在のアセンブリに見えますが、あなたは簡単に別のアセンブリを渡すことができます。

 IEnumerable<Type> types = Assembly.GetExecutingAssembly() 
      .GetTypes().Where(t=>t.GetInterfaces().Where(tt==typeof(IExample)).Count()>0); 
     List<object> objects = new List<object>(); 
     foreach (Type type in types) 
     { 
      objects.Add(Activator.CreateInstance(type)); 
     } 
+0

「Contains」を呼び出してみませんか?また、それは継承を処理しません。 – SLaks

+1

インタフェースのインスタンスを作成できないため、これは失敗します。実装するタイプのインスタンスを作成する必要があります。 –

+0

これは失敗しません!私は型の 't.GetInterfaces()'を呼んでいます。私は私のプロジェクトで同様のものを使用しています。 – Aliostad

8

あなたはで見てアセンブリのリストを知っておく必要があるだろうが、その後LINQはそれが比較的容易になります:

var instances = (from assembly in assemblies 
       from type in assembly 
       where !type.IsAbstract && 
         type.IsClass && 
         type.IsPublic && 
         !type.IsGenericType && 
         typeof(IExample).IsAssignableFrom(type) 
       let ctor = type.GetConstructor(Type.EmptyTypes) 
       where ctor != null && ctor.IsPublic 
       select (IExample) Activator.CreateInstance(type)) 
       .ToList(); 

追加する他のいくつかの制約を考えるかもしれないが、彼らがするのは簡単です特急:

instancesList<IExample>です。

編集:私は私の私の具体的な非クラスを除いているので、あなたの場所ではないコードは動作します。私の推測では、あなたのコードがインターフェイス自体をインスタンス化しようとしている、つまりttypeof(IBootstrapperTask)の場合です。

+0

あなたの返信ありがとう - 詳細については、私のアップデートをご覧ください。 –

+0

@Tomas:編集済み。私の解決策を試しましたか? (必要ならば 'ToArray'に最後の行を変更してください。)確かに、' as'が元のコードに何らかの違いをもたらしたのはなぜですか? –

+0

ありがとう。あなたのコードをもっと見ると、パブリック、非抽象、およびコンストラクタという明示的な要件に気づき、それらを私のコードで実装しました。今、この特定の部分は動作しますが、私は他の(おそらく関連性のない)問題があるので、実際に動作するかどうかを見ることができません。 –

5

これは動的に実行する必要がありますか?あなたが作成したくないものがある時がありますか?これは依存性注入(設定可能)の良いケースであると私には思えます。例えばUnityにはResolveAllメソッドがあります。

上記のリンクから。

IEnumerable<IMyObject> objects = myContainer.ResolveAll<IMyObject>(); 
+0

これは有効な議論ですが、私が質問した限定的な情報しかありませんが、DIは適用されません。 –

+0

ハ - ちょうど私がDIを却下するのがとても速かったからといって、これは私がとにかく終わるところであることが分かった。:Pありがとう!しかし、私は実際の問題を解決するにもかかわらず、答えとしてマークしません。単に質問に答えないからです(「このインターフェースを動的に実装するすべてのクラスをどのように見つけるか」)。 –

+0

+1ありがとうございました!私はCaliburn.Microを使ってMVVMに関連するすべてのものを処理するプロジェクトを構築していましたが、この問題を解決するために使用することはできませんでした。このソリューションが好きな人は、このフレームワークを試してみてください。 – CuddleBunny

関連する問題