简体   繁体   English

使用反射加载外部装配体

[英]Loading External Assembly using reflection

I'm trying to develop an application that supports dynamic loading of external modules. 我正在尝试开发一个支持动态加载外部模块的应用程序。 I have read several articles from loading external assemblies using C# (.NET v4.5) and got the code below. 我已经阅读了一些有关使用C#(.NET v4.5)加载外部程序集的文章,并获得了以下代码。 However, it is not working, not detecting my subclass on the external module. 但是,它不起作用,没有在外部模块上检测到我的子类。

Here is the code for loading external assembly: 这是用于加载外部程序集的代码:

byte[] array = <HERE I LOAD THE DLL>
Assembly asb = Assembly.Load(array);
Type[] types = GetAssemblyTypes(asb);
for( int i = 0; i < types.Length; i++ )
{
    Type t = types[i];
    if( t != null && typeof(App).IsAssignableFrom(t) /*t.IsSubclassOf(typeof(App))*/ )
    {
        app.AppClass = (App)Activator.CreateInstance(t);
        return true;
    }
}

Here is the GetAssemblyTypes() 这是GetAssemblyTypes()

private Type[] GetAssemblyTypes(Assembly asb)
{
    Type[] types;
    try
    {
        types = asb.GetTypes();
    }
    catch( ReflectionTypeLoadException ex )
    {
        types = ex.Types;
    }

    return types;
}

Here is the class on the MAIN APPLICATION (This class will be used by the modules) 这是主应用程序上的类(该类将由模块使用)

namespace MyApplication.API
{
    public class App
    {
       // CODE
    }
}

Here is the example of my module: using MyApplication.API; 这是我的模块示例:使用MyApplication.API;

namespace HelloWorld
{
    class HelloWorld : App
    {

    }
}

Important points are: 1 - I don't know the class name of the module, I just know that it will be a subclass of the App class. 要点是:1-我不知道模块的类名,我只知道它将是App类的子类。

The issue is that although the types.Length gives me 1, when I tries to access by types[i] it gives a null pointer. 问题是,尽管types.Length给我1,但当我尝试通过types [i]访问时却给出了空指针。 Am I missing something here? 我在这里想念什么吗?

I have done something similar to find out if the assembly is derived from my base assembly 我已经做了类似的事情来确定程序集是否源自我的基本程序集

    var assembly = System.Reflection.Assembly.LoadFrom(file);
                AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += CurrentDomain_ReflectionOnlyAssemblyResolve;
                var derivedAssemblies = assembly.GetExportedTypes().Where(w => w.IsSubclassOf(typeof(AddressManager.Base.Connector.ConnectorBase))).Count(); 
                AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve -= CurrentDomain_ReflectionOnlyAssemblyResolve;

                assembly = null;
                if (derivedAssemblies > 0)
                {
                    Manager.LoadAssembly(file, "Connectors");
                    Trace.TraceInformation(" Success! Library loaded.");
                }
                else
                    Trace.TraceInformation(" Skipped! Not a subclass of '" + typeof(AddressManager.Base.Connector.ConnectorBase).Name + "'.");

And handle the ReflectionOnlyAssemblyResolve Event: 并处理ReflectionOnlyAssemblyResolve事件:

   private System.Reflection.Assembly CurrentDomain_ReflectionOnlyAssemblyResolve(object sender, ResolveEventArgs args)
    {
        var assembly = AppDomain.CurrentDomain.GetAssemblies().Where(w => w.FullName == args.Name).FirstOrDefault();
        return assembly;
    }

I got a semi working version based on @CadBurry code. 我有一个基于@CadBurry代码的半工作版本。

byte[] bytes = <HERE I LOAD THE DLL>
Assembly asb = Assembly.Load(bytes);

AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += CurrentDomain_ReflectionOnlyAssemblyResolve;
IEnumerable<Type> types = asb.GetExportedTypes().Where(w => w.IsSubclassOf(typeof(App)));
AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve -= CurrentDomain_ReflectionOnlyAssemblyResolve;
AppDomain.CurrentDomain.AssemblyResolve -= CurrentDomain_AssemblyResolve;

if(types.Count() > 0)
{
    Type type = types.FirstOrDefault();

    if( type == null )
        return false;

    app.AppClass = (App)Activator.CreateInstance(type);
    return true;
}

with the methods: 用的方法:

private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    if( args.Name.Contains(typeof(MyApplication).Assembly.GetName().Name) )
    {
        return Assembly.GetExecutingAssembly();
    }
    return null;
}

private Assembly CurrentDomain_ReflectionOnlyAssemblyResolve(object sender, ResolveEventArgs args)
{
    Assembly asb = AppDomain.CurrentDomain.GetAssemblies().Where(w => w.FullName == args.Name).FirstOrDefault();
    return asb;
}

Using the above code I can load the assembly even when it is not on the current directory of the main application (eg. Plugins folders). 使用上述代码,即使程序集不在主应用程序的当前目录(例如,Plugins文件夹)中,我也可以加载该程序集。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM