您现在的位置是:网站首页> .NET Core

.Net Core利用反射动态加载DLL类库的方法

摘要

Sublevel sublevel = new Sublevel();

            //获取类型

            Type sublevelType = sublevel.GetType();

            //获取类型的方法列表

            //BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public 这个有一个注意点

            //实际上至少要有Instance(或Static)与Public(或NonPublic)标记。否则将不会获取任何方法。

            MethodInfo[] obj = sublevelType.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);

            //遍历所有的方法

            foreach (MethodInfo item in obj)

            {

                //返回方法的返回类型

                Console.Write(item.ReturnType.Name);

                //返回方法的名称

                Console.Write(" "+item.Name+"(");

                //获取方法的返回参数列表

                ParameterInfo[] parameters = item.GetParameters();

                foreach (var parameter in parameters)

                {

                    //参数类型名称

                    Console.Write(parameter.ParameterType.Name);

                    //参数名称

                    Console.Write(" "+parameter.Name+",");

                }

                Console.WriteLine(")");

                //过滤没用方法

                //1:查看是不是有参数的方法

                //2:查看这个方法的返回类型是不是我们想要的

                //3:查看这个方法的返回类型是不是我们想要的

                if (parameters.Any() && 

                    parameters[0].ParameterType == typeof(int) &&

                    item.ReturnType != typeof(void))

                {

                    //调用方法

                    object[] parametersObj = new object[] { 5 };

                    //调用实例方法

                    //第一个参数是我们的实体,后面是我们的参数(参数是一个数组,多个参数按照顺序来传递,没有参数可以为null)

                    //如果我们的方法是一个静态方法 ,这个参数可以为null (不是静态的就会报错)

                    Console.WriteLine(item.Invoke(model, parametersObj));

                }


               

            }

在.Net Framework时代,生成类库只需将类库项目编译好,然后拷贝到其他项目,即可引用或动态加载,相对来说,比较简单。但到了.Net Core时代,动态加载第三方类库,则稍微麻烦一些。

需要在该类库项目的.csproj文件中,在<PropertyGroup></PropertyGroup>标签中加入<EnableDynamicLoading>true</EnableDynamicLoading>标志,该属性将告诉编译器,该项目是动态加载的组件


NET Core3.0 反射异常“System.IO.FileNotFoundException:“Could not load file or assembly

原因为项目的.csproj文件 “<PlatformTarget>x86</PlatformTarget>”,删除这行标签或修改为“Any CPU”即可。



其中Context_Resolving(),是用于加载类库文件过程中,处理触发加载相关依赖文件的事件的方法,通过上述代码,可以保证将类库的完整地动态加载进程序,并且不会与其他动态加载类库项目发生程序集冲突的问题:比如A类库和B类库都有共同的依赖C,但两者的引用的C版本不同,通过AssemblyLoadContext可以保证A/B类库加载自己需要的版本。


using System;

using System.Collections.Generic;

using System.IO;

using System.Reflection;

using System.Runtime.Loader;

 

namespace LoadDLL

{

     /// <summary>

     /// 程序集加载器

     /// </summary>

     public class AssemblyLoader

     {

         private string _basePath;

         private AssemblyLoadContext context;

 

 

         public AssemblyLoader(string basePath)

         {

             _basePath = basePath;

         }

 

         public Type Load(string dllFileName, string typeName)

         {

                 context = new AssemblyLoadContext(dllFileName);

                 context.Resolving += Context_Resolving;

                 //需要绝对路径

                 string path = Path.Combine(_basePath, dllFileName);

                 if (File.Exists(path))

                 {

                     try

                     {

                         using (var stream = File.OpenRead(path))

                         {

                             Assembly assembly = context.LoadFromStream(stream);

                             Type type = assembly.GetType(typeName);

                             dicTypes.Add(typeName, type);

                             return type;

                         }

                     }

                     catch (Exception ex)

                     {

                         Console.WriteLine($"加载节点{dllFileName}-{typeName}发生异常:{ex.Message},{ex.StackTrace}");

                     }

 

                 }

                 else

                 {

                     Console.WriteLine($"节点动态库{dllFileName}不存在:{path}");

                 }            

             return null;

         }

 

         /// <summary>

         /// 加载依赖文件

         /// </summary>

         /// <param name="context"></param>

         /// <param name="assemblyName"></param>

         /// <returns></returns>

         private Assembly Context_Resolving(AssemblyLoadContext context, AssemblyName assemblyName)

         {

             string expectedPath = Path.Combine(_basePath, assemblyName.Name + ".dll"); ;

             if (File.Exists(expectedPath))

             {

                 try

                 {

                     using (var stream = File.OpenRead(expectedPath))

                     {

                         return context.LoadFromStream(stream);

                     }

                 }

                 catch (Exception ex)

                 {

                     Console.WriteLine($"加载节点{expectedPath}发生异常:{ex.Message},{ex.StackTrace}");

                 }

             }

             else

             {

                 Console.WriteLine($"依赖文件不存在:{expectedPath}");

             }

             return null;

         }

     }

 }


Top