2009-07-20 17 views
96

C#では、次のオブジェクトがあります。リフレクションを使用してジェネリックC#オブジェクトを動的に作成する方法

public class Item 
{ } 

public class Task<T> 
{ } 

public class TaskA<T> : Task<T> 
{ } 

public class TaskB<T> : Task<T> 
{ } 

C#リフレクション( Activator.CreateInstance)を使用してTaskAまたはTaskBを動的に作成したいとします。しかし私は手前で型を知っていないので、 "namespace.TaskA"や "namespace.TaskAB"のような文字列に基づいてTaskAを動的に作成する必要があります。

答えて

182

これをチェックアウトするarticlesimple exampleです。あなたのクラスに同じのクイック翻訳...あなたの編集パー

var d1 = typeof(Task<>); 
Type[] typeArgs = { typeof(Item) }; 
var makeme = d1.MakeGenericType(typeArgs); 
object o = Activator.CreateInstance(makeme); 

:そのケースでは、あなたがこれを行うことができます...

var d1 = Type.GetType("GenericTest.TaskA`1"); // GenericTest was my namespace, add yours 
Type[] typeArgs = { typeof(Item) }; 
var makeme = d1.MakeGenericType(typeArgs); 
object o = Activator.CreateInstance(makeme); 

私は名前をbacktick1を思い付いた場所を確認するには汎用クラスのthis articleを参照してください。

注:お使いのジェネリッククラスは複数のタイプを受け入れる場合は、型名を省略したとき、あなたはたとえば、カンマを含める必要があります。

Type type = typeof(IReadOnlyDictionary<,>); 
+0

バックティックが必要ですか?つまり、省略されている場合、コンパイラはそれを1と見なしますか? – richard

+7

私のブログ記事 "Reflectionを使用してC#.Netの一般的なクラスをインスタンス化する"(http://omegacoder.com/?p=38)を「簡単な例」としてリンクしていただきありがとうございます。 :-)私は記事が新しい人生を見つけることがうれしいです。 – OmegaMan

+0

'is'キーワードを使ってジェネリック型を比較す​​るには? –

2

あなたのコード例の最後の行は、単純にする必要があります私には思えます:

Task<Item> itsMe = o as Task<Item>; 

何か不足していますか?

+3

あなたは何も欠けていません。まっすぐ考えていなかったのは私です。私は最後の多くのアルコールを飲んではいけません! – Jeff

6

実際、最後の行を書き込むことはできません。

しかし、オブジェクトを作成したり作成したりするのではなく、オブジェクトを作成したいと思うかもしれません。新しく作成されたインスタンスでいくつかのメソッドを呼び出すことをお勧めします。

あなたは、インターフェイスのようなものが必要です:

public interface ITask 
{ 
    void Process(object o); 
} 

public class Task<T> : ITask 
{ 
    void ITask.Process(object o) 
    { 
     if(o is T) // Just to be sure, and maybe throw an exception 
     Process(o as T); 
    } 

    public void Process(T o) { } 
} 

をし、それを呼び出します。いずれにせよ

Type d1 = Type.GetType("TaskA"); //or "TaskB" 
Type[] typeArgs = { typeof(Item) }; 
Type makeme = d1.MakeGenericType(typeArgs); 
ITask task = Activator.CreateInstance(makeme) as ITask; 

// This can be Item, or any type derived from Item 
task.Process(new Item()); 

、あなたは静的に、あなたが「ドン型にキャストされることはありませんあらかじめ知っている(この場合は "makeme")。 ITaskを使用すると、目標のタイプに到達することができます。

これがあなたの望むものでない場合は、おそらくこれで達成しようとしていることに少し具体的にする必要があります。

+0

ホー、質問は変更されました:) –

+0

私はタスクのProcess()のようなものを持っています。そして、私の場合、実際には、あなたが単にtask.Process()を呼び出すと、最後の行をコード化することができないかどうかは分かりません。 – Jeff

1

以下のような単純な関数を使用すると、「参照の検索」や「リファクタリング」 - >「名前の変更」などのIDEでの入力が可能になります。

public Task <T> factory (String name) 
{ 
    Task <T> result; 

    if (name.CompareTo ("A") == 0) 
    { 
    result = new TaskA(); 
    } 
    else if (name.CompareTo ("B") == 0) 
    { 
    result = new TaskB(); 
    } 

    return result; 
} 
+0

なぜあなたは.CompareToを使用していますか?なぜ==や.Equals(あなたがもっとコントロールしたいのであれば)?多分スイッチがあればさらに良いでしょう。 – Zyphrax

+0

参照比較の代わりに==で文字列比較を行うかどうかは決して確認しませんでした。 CompareToとEqualsは、正しく実装されていれば実行時の効率が同じでなければなりません。スイッチブロックは、スイッチブロック内に整数を置くのと同じスピードアップを持たない。それはif-elseブロックにコンパイルされます。 – clemahieu

1

私はこの問題が解決されていることを知っていますが、それを読む他の人の利益のためです。あなたは文字列として関与タイプのすべてを持っている場合、あなたは1つのライナーとしてこれを行うことができます:私はこの種のものをやった時はいつでも

IYourInterface o = (Activator.CreateInstance(Type.GetType("Namespace.TaskA`1[OtherNamespace.TypeParam]") as IYourInterface); 

、私が利用するために、後続のコードを望んでいたインターフェースを持っていました私は作成したインスタンスをインターフェイスにキャストしました。

関連する問題