在C#中,我有以下对象:
public class Item
{ }
public class Task<T>
{ }
public class TaskA<T> : Task<T>
{ }
public class TaskB<T> : Task<T>
{ }
我想使用C#reflection( Activator.CreateInstance )动态创建TaskA或TaskB。但是我不知道手头的类型,所以我需要基于像“namespace.TaskA”或“namespace.TaskAB”这样的字符串动态创建TaskA。
答案 0 :(得分:223)
查看此article和此simple 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<,>);
答案 1 :(得分:7)
的确,你无法写下最后一行。
但您可能不想创建对象,只是为了起见或创建它。您可能想在新创建的实例上调用某个方法。
然后你需要一个类似界面的东西:
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允许您到达目标类型。
如果这不是您想要的,那么您可能需要更加具体地了解您想要实现的目标。
答案 2 :(得分:2)
在我看来,示例代码的最后一行应该只是:
Task<Item> itsMe = o as Task<Item>;
或者我错过了什么?
答案 3 :(得分:1)
确保你这样做有充分的理由,像下面这样的简单函数允许静态输入,并允许你的IDE做“查找引用”和重构 - &gt;等操作。重命名。
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;
}
答案 4 :(得分:1)
我知道这个问题已经解决了,但为了其他人阅读它的利益;如果您将所有类型都作为字符串包含在内,则可以将其作为一个内容:
IYourInterface o = (Activator.CreateInstance(Type.GetType("Namespace.TaskA`1[OtherNamespace.TypeParam]") as IYourInterface);
每当我做完这种事情时,我就有了一个我希望后续代码可以使用的接口,所以我将创建的实例转换为接口。