如何使用反射动态创建通用的 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。但是我事先不知道类型,所以我需要基于类似“名称空间”的字符串动态创建 TaskA。TaskA”或“名称空间”。TaskAB”。

186457 次浏览

看看这个 文章和这个 举个简单的例子。快速翻译同样到你的类..。

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

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

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

还是我错过了什么?

事实上,你不能写最后一行。

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

然后你需要一个类似于接口的东西:

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

在任何情况下,您都不会被静态强制转换为事先不知道的类型(在本例中为“ make me”)。ITask 允许你找到你的目标类型。

如果这不是你想要的,你可能需要更具体一点,你试图实现这一点。

请确保您这样做是有充分理由的,下面这样一个简单的函数将允许静态输入,并允许 IDE 执行“ Find References”和“ Refactor-> Rename”之类的操作。

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

每当我做这样的事情,我已经有了一个接口,我希望后续代码利用,所以我已经铸造了一个接口创建的实例。