如何使用反射动态创建通用C#对象?

如何使用反射动态创建通用C#对象?,c#,generics,reflection,activator,C#,Generics,Reflection,Activator,在C#中,我有以下对象: public class Item { } public class Task<T> { } public class TaskA<T> : Task<T> { } public class TaskB<T> : Task<T> { } 公共类项目 { } 公开课任务 { } 公共类TaskA:任务 { } 公共类TaskB:任务 { } 我想使用C#反射(Activator.CreateInstan

在C#中,我有以下对象:

public class Item
{ }

public class Task<T>
{ }

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

public class TaskB<T> : Task<T>
{ }
公共类项目
{ }
公开课任务
{ }
公共类TaskA:任务
{ }
公共类TaskB:任务
{ }
我想使用C#反射(Activator.CreateInstance)动态创建TaskA或TaskB。但是,我现在还不知道类型,所以我需要基于“namespace.TaskA”或“namespace.TaskAB”之类的字符串动态创建TaskA。快速将其翻译到您的课堂上

var d1 = typeof(Task<>);
Type[] typeArgs = { typeof(Item) };
var makeme = d1.MakeGenericType(typeArgs);
object o = Activator.CreateInstance(makeme);
要查看我在哪里为泛型类的名称找到backtick1,请参阅

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

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

在我看来,示例代码的最后一行应该是:

Task<Item> itsMe = o as Task<Item>;
Task itsMe=o作为任务;

还是我遗漏了什么?

事实上,你将无法写出最后一行

但是您可能不想创建对象,只是为了创建它。您可能希望在新创建的实例上调用某些方法

然后,您将需要类似于接口的东西:

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) { }
}
在任何情况下,您都不会被静态地强制转换为您事先不知道的类型(在本例中为“makeme”)。ITask允许您访问目标类型


如果这不是您想要的,那么您可能需要更具体地说明您试图用它实现的目标。

请确保这样做是有充分理由的,下面这样的简单函数将允许静态键入,并允许您的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;
}
公共任务工厂(字符串名称)
{
任务结果;
如果(name.CompareTo(“A”)==0)
{
结果=新任务a();
}
else if(name.CompareTo(“B”)==0)
{
结果=新任务b();
}
返回结果;
}

我知道这个问题已经解决了,但是为了其他读者的利益;如果所有类型都是字符串,则可以将其作为一行程序:

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

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

您不会遗漏任何东西。是我思维不清。昨晚我不该喝那么多酒!我的任务中确实有类似Process()的东西。在我的例子中,我实际上不再关心最后一行,正如你所说的,我只是调用task.Process(),因此,是否能够编写最后一行代码就变得无关紧要了。你为什么要使用.CompareTo?为什么不==或.Equals(如果您想要更多的控制)。也许一个开关会更好。我从未检查过C#是否对==进行字符串比较,而不是引用比较。如果正确实现,CompareTo和Equals应该具有相同的运行时效率。一个开关块的速度不会像在开关块中放入一个整数那样快;它将编译为if-else块。是否需要反勾号,即,如果它是ommited,编译器是否假定它为1?感谢您链接到我的博客文章“使用反射在C#.Net中实例化泛型类”(作为“简单示例”):-)我很高兴这篇文章找到了新的生命。我如何使用
is
关键字来比较泛型类型?您也可以使用Activator.CreateInstance,这样就无需创建指定“typeargs”并自己创建泛型类型。Francis Dean,关键是您有类型对象,并且无法将其放置在
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;
}
IYourInterface o = (Activator.CreateInstance(Type.GetType("Namespace.TaskA`1[OtherNamespace.TypeParam]") as IYourInterface);