【问题标题】:Create an instance of a class from a string从字符串创建类的实例
【发布时间】:2020-07-30 05:33:00
【问题描述】:

有没有办法根据我在运行时知道类的名称这一事实来创建类的实例。基本上我会把类的名字放在一个字符串中。

【问题讨论】:

  • 您似乎已经描述了您要实施的解决方案,但没有描述您要解决的问题。也许您正在尝试做一些可扩展的事情,在这种情况下,我建议您查看Managed Extensibility Framework

标签: c# .net instantiation system.type


【解决方案1】:

看看Activator.CreateInstance方法。

【讨论】:

【解决方案2】:

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

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

如果您的Fully Qualified Name(即在这种情况下为Vehicles.Car)在另一个程序集中,则Type.GetType 将为空。在这种情况下,您将遍历所有程序集并找到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 - 为了使用类实例,您需要了解它要做什么 - 否则您将无法使用它。最常见的用例是转换为某个接口,该接口为您提供预定义的合同。 (除非您使用dynamic 代码,否则这成立 - 请参阅stackoverflow.com/a/2690661/904521
  • 不要在变量名中编码变量的类型。例如:不需要在strFullyQualifiedName前加上strfullyQualifiedName就可以了。
  • 关键字str 用作变量命名约定的一部分。某些组织和项目坚持遵循这一点,因此我使用了。如果您曾在某些组织/项目中工作过,您就会知道这一点。正如你所说,没有str 也可以完成这项工作:) @MehdiDehghani
  • 我知道,没有必要在任何组织中工作来了解命名约定,这种约定称为Hungarian notation,它是一种糟糕的和已弃用命名大会在那里。专门用于 C#
【解决方案3】:

我已经成功使用了这个方法:

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

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

【讨论】:

  • 我试图想象这样一个场景,通过类名创建对象,然后将其转换为该类型完全有意义。
  • 我明白你的意思。似乎是多余的。如果您知道类名,为什么需要动态字符串?一种情况可能是您转换为基类,而字符串表示该基类的后代。
  • 如果基类已知,则可以使用基类或它的接口作为参数传递后代而不反射。
  • 有用的场景:你只需要序列化接口,或者任何其他相当常见的接口。您不会将其强制转换为类,但至少不会强制转换为对象
  • 如何从给定的字符串进行强制转换??
【解决方案4】:

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

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

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

【讨论】:

  • 建议您编辑您的问题并注意更改,而不是在问题部分中回复。这样做你会得到更多/更好的答案。
  • 感谢您发布对您有用的特定代码行。对所有 CreateInstance 重载和生成类型的不同方式进行排序花费了我很多时间,而这为我节省了时间。
【解决方案5】:

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

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

【讨论】:

    【解决方案6】:

    我知道我迟到了...但是您正在寻找的解决方案可能是上述的组合,并使用接口来定义您的对象可公开访问的方面。

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

    【讨论】:

      【解决方案7】:

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

      【讨论】:

        【解决方案8】:
        ReportClass report = (ReportClass)Activator.CreateInstance(Type.GetType(reportClass));
        

        你为什么要写这样的代码?如果你有一个类'ReportClass'可用,你可以直接实例化它,如下所示。

        ReportClass report = new ReportClass();
        

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

        我的意思是当你知道程序集但在编写代码时你没有可用的 ReportClass 类时它很有用。

        【讨论】:

        • ReportClass 可以是基类或接口
        猜你喜欢
        • 1970-01-01
        • 2015-07-22
        • 1970-01-01
        • 2011-04-14
        • 2012-02-26
        • 1970-01-01
        • 1970-01-01
        • 2011-04-09
        相关资源
        最近更新 更多