从字符串创建类的实例


217

有一种方法可以基于我在运行时知道该类的名称的事实来创建该类的实例。基本上,我会在字符串中包含类的名称。


您似乎已经描述了要实现的解决方案,但没有描述您要解决的问题。也许您正在尝试使用可扩展性做某事,在这种情况下,我建议您查看Managed Extensibility Framework
杰伊·巴祖兹

Answers:


159

看一下Activator.CreateInstance方法。


15
相关与伟大的例子: stackoverflow.com/questions/493490/...
约翰S.

另外这个职位将是相关的,以及,作为你的类型需要被发现:stackoverflow.com/questions/1825147/...
布拉德·公园


4
例如:var driver = (OpenQA.Selenium.IWebDriver)Activator.CreateInstance("WebDriver", "OpenQA.Selenium.Firefox.FirefoxDriver").Unwrap();
Endy Tjahjono 2014年

2
此处的重要说明:.Unwrap()可以绕过远程句柄,因此您实际上可以进行强制转换。@Endy-谢谢
Roger Willcocks

77

非常简单。假设您的类名是Car,名称空间是Vehicles,然后传递参数,Vehicles.Car该参数返回type的对象Car。这样,您可以动态创建任何类的任何实例。

public object GetInstance(string strFullyQualifiedName)
{         
     Type t = Type.GetType(strFullyQualifiedName); 
     return  Activator.CreateInstance(t);         
}

如果您的全名(例如,Vehicles.Car在本例中)在另一个程序集中,则该名称Type.GetType将为null。在这种情况下,您将遍历所有程序集并找到Type。为此,您可以使用以下代码

public object GetInstance(string strFullyQualifiedName)
{
     Type type = Type.GetType(strFullyQualifiedName);
     if (type != null)
         return Activator.CreateInstance(type);
     foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
     {
         type = asm.GetType(strFullyQualifiedName);
         if (type != null)
             return Activator.CreateInstance(type);
     }
     return null;
 }

现在,如果要调用参数化的构造函数,请执行以下操作

Activator.CreateInstance(t,17); // Incase you are calling a constructor of int type

代替

Activator.CreateInstance(t);

如何在不进行强制转换的情况下使用它,以及如何从给定的字符串进行强制转换?
TaW 2016年

1
@TaW-为了使用一个类实例,您将需要知道它将要做什么-否则您将无法使用它。最常见的用例是转换为某些接口,该接口为您提供了预定义的合同。(这适用,除非你使用的dynamic代码-见stackoverflow.com/a/2690661/904521
托默卡根

1
不编码变量的类型在它的名称,例如:没有必要前缀strFullyQualifiedNamestrfullyQualifiedName将做的工作。
Mehdi Dehghani

关键字str用作变量命名约定的一部分。某些组织和项目坚持要遵循此原则,因此我使用了。如果您曾在某些组织机构/项目中工作过,您将知道这一点。正如您所说的,str它也可以完成工作:) @MehdiDehghani
Sarath Avanavu 19/12/14

1
我知道,尽管有任何组织需要了解命名约定,但该约定被称为匈牙利符号,它是其中一种不好的且已弃用的命名约定。专为C#设计
Mehdi Dehghani

55

我已成功使用此方法:

System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(string className)

您需要将返回的对象转换为所需的对象类型。


9
我正在尝试设想一个场景,即通过类名称创建对象,然后将其强制转换为该类型将毫无意义。
MusiGenesis'Oct 21'08

13
我明白你的意思了。似乎多余。如果知道类名,为什么需要动态字符串?一种情况可能是您强制转换为基类,并且字符串表示该基类的后代。
Ray Li

4
如果已知基类,则可以使用基类或其接口作为参数来传递后代而不进行反射。
Garet Claborn 2014年

3
有用的场景:您只需要序列化接口或任何其他非常普通的接口。您不会将其投放到班级,但至少会投放到对象之外的东西
Harald Coppoolse 2014年

2
如何从给定的字符串进行转换
TaW 2016年

23

也许我的问题应该更具体。我实际上知道该字符串的基类,因此通过以下方式解决了该问题:

ReportClass report = (ReportClass)Activator.CreateInstance(Type.GetType(reportClass));

Activator.CreateInstance类具有多种方法,可以以不同的方式实现同​​一件事。我本可以将其转换为对象,但以上内容对我的情况最有用。


4
建议您编辑问题并记录更改,而不是在问题部分中进行答复。您将获得更多/更好的答案。
杰森·杰克逊

感谢您发布适合您的特定代码行。整理所有CreateInstance重载和不同的生成Types的方法花了我很多时间,您节省了我。
Ethel Evans

4

我知道我来晚了...但是您要寻找的解决方案可能是上述方法的结合,并使用界面来定义对象的公共可访问方面。

然后,如果将通过这种方式生成的所有类都实现了该接口,则只需将其转换为接口类型并使用生成的对象即可。


4

要从解决方案中的另一个项目创建一个类的实例,您可以获取由任何类的名称指示的程序集(例如BaseEntity)并创建一个新实例:

  var newClass = System.Reflection.Assembly.GetAssembly(typeof(BaseEntity)).CreateInstance("MyProject.Entities.User");

3

例如,如果您将各种类型的值存储在数据库字段中(存储为字符串),并且具有另一个具有类型名称的字段(即String,bool,int,MyClass),那么可以想象到,从该字段数据中,使用上面的代码创建任何类型的类,并使用第一个字段中的值填充它。当然,这取决于要存储的类型,该类型具有将字符串解析为正确类型的方法。我已经多次使用它来将用户首选项设置存储在数据库中。


-11
ReportClass report = (ReportClass)Activator.CreateInstance(Type.GetType(reportClass));

您为什么要编写这样的代码?如果您有可用的类“ ReportClass”,则可以直接实例化它,如下所示。

ReportClass report = new ReportClass();

ReportClass report = (ReportClass)Activator.CreateInstance(Type.GetType(reportClass));当您没有必要的可用类,但要实例化和/或动态调用方法时,将使用该代码。

我的意思是,当您了解程序集时它很有用,但是在编写代码时您没有ReportClass可用的类。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.