如何从C#中的字符串创建generics类?

我有一个像这样的Generic类:

public class Repository {...} 

我需要用字符串来实例…示例:

 string _sample = "TypeRepository"; var _rep = new Repository(); 

我怎样才能做到这一点? 这有可能吗?

谢谢!

这是我的2美分:

 Type genericType = typeof(Repository<>); Type[] typeArgs = { Type.GetType("TypeRepository") }; Type repositoryType = genericType.MakeGenericType(typeArgs); object repository = Activator.CreateInstance(repositoryType); 

回答评论中的问题。

 MethodInfo genericMethod = repositoryType.GetMethod("GetMeSomething"); MethidInfo closedMethod = genericMethod.MakeGenericMethod(typeof(Something)); closedMethod.Invoke(repository, new[] { "Query String" }); 

首先使用Type.GetType(stringContainingTheGenericTypeArgument)获取Type对象Type.GetType(stringContainingTheGenericTypeArgument)

然后使用typeof(Repository<>).MakeGenericType(theTypeObject)来获取generics类型。

最后使用Activator.CreateInstance

这是C#4.0中dynamic关键字的工作。

这里有一些不错的黑客可以让你获得你的对象的实例,但无论当前版本的C#只知道它有一个object ,并且它对一个对象本身无法做太多因为当前的C#没有支持后期绑定。 您需要能够至少将其转换为已知类型以对其执行任何操作。 最终,您必须在编译时知道所需的类型否则您将失去运气。

现在,如果您可以将存储库类限制为实现某个已知接口的类型,那么您的形状会更好。

如果我正确理解你的问题……你要做的是采用你的类型(Repository )并在运行时构建一个特定的通用实现?

如果是这样,请查看MakeGenericType 。 您可以使用typeof(Repository)和T所需对象的System.Type并以这种方式构造它。 一旦你有了类型,Activator.CreateInstance将适合你。

假设您的字符串包含类型的名称,您可以编写

 object _rep = Activator.CreateInstance(typeof(Repository<>).MakeGenericType(Type.GetType(_sample))); 

但是,_rep将是一个无类型的对象,你将无法用它做任何事情。 由于您不知道generics类在编译时的类型,因此没有将其强制转换为的类型。 (除非Repositoryinheritance非generics类或实现非generics接口)

您可以通过为Repository创建一个非generics基类并将对象转换为它来解决这个问题。

但是,根据您的具体情况,您可能希望将Repository设为非generics类。

如果Repository是包含其他类的类,则最好将其设置为非generics。 您可以使其构造函数采用Type对象,然后对您添加的每个对象调用Type.IsInstanceOfType ,以确保它是正确的类型。

如果Repository是一个分类的事物集合,那么最好使它成为非generics的,并使其构造函数采用string category

如果您需要更具体的建议,请发布有关您情况的更多详细信息。

 Type repType = typeof(Repository <>).MakeGenericType(Type.GetType("System.String")); object rep = Assembly.GetAssembly(repType).CreateInstance(repType.FullName); 

这将创建一个Repository的实例。 您可以将“System.String”替换为您喜欢的任何类型。

generics可以处理类型,而不是实例。 你可以在这里阅读更多。

听起来你只需要在你的类中添加一个构造函数,它接受所需的类型并初始化值:

 public class Foo { private T = default(T); public Foo(T initValue) { _val = T; } } 

这有点“可行”。 你可以做到这一点,但它有点像黑客。

你有3个选择:

如果您事先知道了类,请使用switch语句。 基本上是这样的:

 switch(str){ case "TypeRepository": return new Repository; } 

作为上述的更高级forms,您可以使用字典而不是哈希表

 var factory = new Dictionary>(); factory.Add( "TypeRepository", () => new Repository() ); var theObject = factory["TypeRepository"]() as Repository; 

为了获得最大的灵活性,您可以使用reflection在运行时将字符串与类匹配。 请注意,reflection速度相当慢,所以如果你以任何规律性做这件事,你都要避免它。 举个例子,这是一个使用Frans Bouma的方法。 只需在代码中将List<>更改为Repository<>

 public static object MakeList( string typeStr ) { var nameSpace = "MyTestApplication" + "."; var objType = Type.GetType(nameSpace + typeStr); // NAMESPACE IS REQUIRED var listType = typeof(List<>).MakeGenericType(objType); return Activator.CreateInstance(listType); } var listOfThings = MakeList("MyCoolObject") as List; 

注意:没有办法避免所有这些机制返回object的事实,然后您必须将其转换为正确的类型,而不是返回仅返回强类型值。

这是不可避免的,因为在运行时你不知道列表的类型,而C#是在编译时知道事物的(这就是人们说“静态类型编程语言”时的意思)。 在C#4中你将会减少痛苦,你将能够返回dynamic ,这将节省你的演员阵容。

Generic类中的“T”代表类型,而不是类型的实例。 因此,如果您希望存储库保存字符串对象,请使用

 var _rep = new Repository();