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);

要查看我在哪里为泛型类的名称想出了反引号,请参阅这篇文章

注意:如果您的泛型类接受多种类型,则在省略类型名称时必须包含逗号,例如:

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

我知道这个问题已经解决了,但是为了其他阅读它的人的利益;如果您将所有类型都作为字符串涉及,则可以将其作为一个衬里执行:

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

每当我做这种事情时,我都有一个接口,我希望后续代码可以使用它,所以我将创建的实例转换为接口。

于 2013-10-24T10:13:04.463 回答
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 回答