开发者

Reflection - Can't create a new object instance C#

I am trying to create a plug-in type archetecure for my project. I would like the ability to load an assembly, get a type that is derived from an abstract base class in my project, instantiate it and load that derived type into the main processing object.

My problem right now is that when I instantiate the object from the reflected assembly, it is always null. I feel that the problem may lie in the fact that the referenced assembly has 3rd party dlls that it is using. Here is the code: the only exception that gets hit is the final one.

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;
}

If I change the instantiation line to Activator.CreateInstance(engineType), I receive an error saying that one of t开发者_Go百科he 3rd party dll's being referenced by the reflected assembly can't be found, though they are in the same directory as the .dll being reflected.

There is a public constructor for the type that is being reflected as well. It has no parameters and inherits from the EngineConcrete class.


I think null is what you get when the type can't be found; the namespace name plus the type name may not be sufficient (strong naming issues). What happens if you put the 3rd-party dlls in the directory of the executing application, not the directory of the plugin?


This is the bug: engineType.Namespace + "." + engineType — this expression evaluates into "The.Namespace.The.Namespace.Type" instead of "The.Namespace.Type". Either use engineType.FullName or the Activator.CreateInstance class and use the engineType directly.

Update: Note that MSDN says “… or null if typeName is not found.” about Assembly.CreateInstance's return value.


The issue is that the CLR is not finding the third-party assemblies because they are not in a folder that is being probed.

You could add an event handler for the AppDomain.CurrentDomain.AssemblyResolve event to handle those cases. Below is an example implementation that worked for me where assemblies are being dynamically loaded from a "Plugins" folder that is contained within the bin folder:

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!"));
        }
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜