142

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を作成する必要があります。

4

5 に答える 5

267

この記事とこの簡単な例を確認してください。あなたのクラスへの同じもののクイック翻訳...

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を思いついた場所を確認するには、この記事を参照してください。

注:ジェネリッククラスが複数の型を受け入れる場合は、型名を省略するときにコンマを含める必要があります。次に例を示します。

Type type = typeof(IReadOnlyDictionary<,>);
于 2009-07-20T02:02:34.877 に答える
8

確かに、最後の行を書くことはできません。

ただし、オブジェクトを作成するためだけに、オブジェクトを作成したくない場合もあります。新しく作成したインスタンスで何らかのメソッドを呼び出したいと思うかもしれません。

次に、インターフェースのようなものが必要になります。

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を使用すると、ターゲットタイプに到達できます。

これが希望どおりでない場合は、これを使用して達成しようとしていることをもう少し具体的にする必要があります。

于 2009-07-20T02:49:26.850 に答える
3

サンプルコードの最後の行は、次のようになります。

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

それとも私は何かが足りないのですか?

于 2009-07-20T02:35:06.283 に答える
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;
}
于 2009-07-21T22:46:46.220 に答える
1

私はこの質問が解決されたことを知っていますが、それを読んでいる他の人の利益のために。すべてのタイプが文字列として含まれている場合は、これを1つのライナーとして実行できます。

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

この種のことを行うときはいつでも、後続のコードで利用したいインターフェースを持っていたので、作成したインスタンスをインターフェースにキャストしました。

于 2013-10-24T10:13:04.463 に答える