如何动态实例化一个类?

时间:2018-03-26 14:10:26

标签: c#

var typeName = $"Drv{id}.Fonte";
var type = Type.GetType(typeName);
var myObject = Activator.CreateInstance(type);

Drv {id}是我的命名空间,Fonte是类名。

为什么'type'始终为null?

当我打电话给第三行时,我明白了:

  

System.ArgumentNullException:'值不能为空。'

this

enter image description here

4 个答案:

答案 0 :(得分:2)

我将详细阐述实际部分。

正如其他人所说,你需要装配合格的名字。 为什么?那么看看Type.GetType(string typeName)方法的评论。

  

参数:

     

// typeName:
  //要获取的类型的程序集限定名称。请参见System.Type.AssemblyQualifiedName。

     

// 如果类型在当前正在执行的程序集 或Mscorlib.dll中,则提供由其名称空间限定的类型名称就足够了。

请注意,只有 if 类型在当前正在执行的程序集中才足以像你一样调用它。

我在另一个项目中有一个类,我的主项目就像你一样。

using System.Reflection;

namespace Test2
{
    public class Class1
    {
        public string CallMe()
        {
            return Assembly.GetExecutingAssembly().FullName;
        }
    }
}

然后我这样称呼它:

using System;
using System.Reflection;
using Test2;

namespace NetCore2._0
{
    class Program
    {
        static void Main(string[] args)
        {
            var typeName = typeof(Test2.Class1).AssemblyQualifiedName;
            var type = Type.GetType(typeName);

            Console.WriteLine(Assembly.GetExecutingAssembly().FullName);
            var myObject = Activator.CreateInstance(type) as Class1;
            Console.WriteLine(myObject.CallMe());
        }

    }
}

我希望你能看到差异在哪里以及为什么你现在需要提供合格的名字。

答案 1 :(得分:1)

您需要Assembly qualified name。正如MSDN所述。

示例(来自MSDN链接):

  

TopNamespace.SubNameSpace.ContainingClass + NestedClass,MyAssembly程序

答案 2 :(得分:1)

用于实例化类型的字符串格式错误。

来自Type.GetType(String)的文档:

  

typeName:String

     

要获取的类型的程序集限定名称。看到   AssemblyQualifiedName。如果类型在当前正在执行   汇编或在Mscorlib.dll中,提供类型名称就足够了   由其命名空间限定。

来源:Type.GetType Method

来自AssemblyQualifiedName的文档:

  

类型的程序集限定名称由类型名称组成,   包括其命名空间,后跟逗号,后跟显示   程序集的名称。获得组件的显示名称   使用Assembly.FullName属性。

     

例如,类的程序集限定名称可能如下所示   这样:

     

TopNamespace.SubNameSpace.ContainingClass + NestedClass,MyAssembly,   Version = 1.3.0.0,Culture = neutral,PublicKeyToken = b17a5c561934e089

答案 3 :(得分:1)

我最近写了这段代码。我需要在运行时实例化一个对象,就像你一样,但遇到了类的位置的几个问题(不同的程序集,作为vshost运行,作为IISExpress运行)。

这是一个非常通用的场景,因此对您的需求可能有点过分......

private static Type GetType(string typeName)
{
    // check executing assembly
    var type = Assembly
        .GetExecutingAssembly()
        .GetTypes()
        .FirstOrDefault(x => x.FullName == typeName);

    // if not found check referenced assemblies
    if (type == null)
    {
        type = Assembly
            .GetExecutingAssembly()
            .GetReferencedAssemblies()
            .Select(Assembly.Load)
            .SelectMany(x => x.GetTypes())
            .FirstOrDefault(x => x.FullName == typeName);
    }

    // if still not found check all suitably named assemblies in executing folder
    if (type == null)
    {
        var files = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.dll");

        if (files.Length == 0)
        {
            files = Directory.GetFiles(AppDomain.CurrentDomain.RelativeSearchPath, "*.dll");
        }

        files.ToList().ForEach(filename =>
        {
            if (type == null)
            {
                var assembly = Assembly.LoadFile(filename);
                var castableAssembly = AppDomain.CurrentDomain.Load(assembly.GetName());
                type = castableAssembly.GetTypes().FirstOrDefault(x => x.FullName == typeName);
            }
        });
    }

    return type;
}

这将返回null或可以与Activator.CreateInstance()一起使用的类型,并且您知道它可以访问。在您的情况下,将您的代码更改为...

var typeName = $"Drv{id}.Fonte";
var type = GetType(typeName); // using the above method
var myObject = Activator.CreateInstance(type);

这不是性能友好的代码,但除非您经常这样做,或者您的工作目录有大量的程序集,否则您不必担心它。如果您正在做很多事情或者您有大量的装配,那么您应该重新考虑整体设计。