反射 - 无法创建新的对象实例C#

时间:2010-10-13 21:13:36

标签: c# .net reflection

我正在尝试为我的项目创建一个插件类型的archetecure。我希望能够加载程序集,获取从我的项目中的抽象基类派生的类型,实例化它并将该派生类型加载到主处理对象中。

我现在的问题是,当我从反射的程序集中实例化对象时,它始终为null。我觉得问题可能在于引用的程序集具有正在使用的第三方dll。这是代码:被击中的唯一例外是最后一个。

static void Main(string[] args)
{
    string engineFilePath = ConfigurationManager.AppSettings["EngineFilesDirectory"]
        + "\\" + ConfigurationManager.AppSettings["EngineDllFileName"];
    Assembly asm = Assembly.LoadFile(engineFilePath);

    Type engineType = asm.GetType(ConfigurationManager.AppSettings["EngineType"]);

    if (!engineType.IsSubclassOf(typeof(EngineConcrete)))
    {
        throw new ArgumentException("Engine is not derived from base implimentation.");
    }

    object engineInstance = asm.CreateInstance(engineType.Namespace + "." + engineType);


    if (engineInstance == null)
    {
       //always thrown at this point
        throw new Exception(string.Format("Engine object is null."));
    }

    return;
}

如果我将实例化行更改为Activator.CreateInstance(engineType),则会收到一条错误消息,指出无法找到反射程序集引用的第三方dll之一,尽管它们位于同一目录中。 dll被反映出来。

还有一个正在反映的类型的公共构造函数。它没有参数,并且继承自EngineConcrete类。

3 个答案:

答案 0 :(得分:1)

这是错误:engineType.Namespace + "." + engineType - 此表达式的计算结果为"The.Namespace.The.Namespace.Type"而不是"The.Namespace.Type"。使用engineType.FullNameActivator.CreateInstance类并直接使用engineType

更新:请注意,MSDN说“...如果找不到typeName,则为null。”关于Assembly.CreateInstance的返回值。

答案 1 :(得分:1)

我认为null是无法找到类型时得到的;命名空间名称加上类型名称可能不够(强命名问题)。如果将第三方dll放在正在执行的应用程序的目录中而不是插件的目录中会发生什么?

答案 2 :(得分:0)

问题是CLR没有找到第三方程序集,因为它们不在被探测的文件夹中。

您可以为AppDomain.CurrentDomain.AssemblyResolve事件添加事件处理程序来处理这些情况。下面是一个示例实现,适用于从bin文件夹中包含的“Plugins”文件夹动态加载程序集的示例:

class Program
{
    static string _PluginDirectory;
    static string PluginDirectory
    {
        get
        {
            if (_PluginDirectory == null)
            {
                _PluginDirectory = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), @"Plugins");
            }
            return _PluginDirectory;
        }
    }

    static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        AssemblyName assemblyName = new AssemblyName(args.Name);
        return Assembly.LoadFile(System.IO.Path.Combine(PluginDirectory, assemblyName.Name + ".dll"));
    }

    static void Main(string[] args)
    {
        AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

        var asm = Assembly.LoadFile(System.IO.Path.Combine(PluginDirectory, @"Plugin.dll"));

        var transmogrifier = asm.CreateInstance("Plugin.ConcreteTransmogrifier") as Common.Transmogrifier;

        if (transmogrifier != null)
        {
            Console.WriteLine(transmogrifier.Transmogrify("Wowzers!"));
        }
    }
}