当前位置:网站首页>反射获取DLL中的字段、属性、方法、泛型方法(C#)

反射获取DLL中的字段、属性、方法、泛型方法(C#)

2022-08-11 11:07:00 草原上唱山歌

在C#中,调用DLL文件时,使用Assembly类中的静态方法,常用的Assembly类方法有Load()LoadFrom()LoadFile()
这三种方法的区别和细节:

Assembly.Load()

Load方法的参数可以为stringAssemblyName类型,这个参数实际上是需要加载程序集的强名称(名称、版本、语言、公钥标记),例如在.NET 2.0中的FileIOPermission类,它的强名称类是:
System.Security.Permissions.FileIOPermission(名称), mscorlib, Version=2.0.0.0(版本), Culture=neutral, PublicKeyToken=b77a5c561934e089(公钥标记)
对于弱命名的程序集,则只需要程序集名称,而不需要版本、语言和公钥标记。

细节:

1.CLR内部普遍使用Load()方法加载程序集,在Load()方法内部,CLR首先会应用这个程序集的版本绑定重定向策略,接着在GAC中查找目标程序集。如果GAC中没有找到,则会在应用程序目录和子目录中寻找(应用配置文件的codebase所指定的位置)。

2.如果希望加载弱命名程序集,Load()方法就不会去GAC中查找。

3.当Load()找到目标程序集时,就会加载它,并返回一个相应Assembly对象的引用。

4.当没有找到程序集时,会抛出System.IO.FileNotFoundException异常。

5.当存在特定CPU架构的程序集时,CLR会优先加载当前架构的程序集(例如x86版本优先于IL中立版本)。

6.如果希望强迫加载某个架构版本的程序集,需要在强名称中加以指定。ProcessorArchitecture可以为x86 IA64 AMD64或MSIL,当然还有None。

7.Load方法与Win32函数中的LoadLibrary方法等价。

Assembly.LoadFrom()

LoadFrom方法可以从指定文件中加载程序集,通过查找程序集的AssemblyRef元数据表,得到所有引用和需要的程序集,然后在内部调用Load()方法进行加载。

细节:

1.LoadFrom()首先会打开程序集文件,通过GetAssemblyName方法得到程序集名称,然后关闭文件,最后将得到的AssemblyName对象传入Load()方法中。
2.随后,Load()方法会再次打开这个文件进行加载。所以,LoadFrom()加载一个程序集时,会多次打开文件,造成了效率低下的现象(与Load相比)。
3.由于内部调用了Load(),所以LoadFrom()方法还是会应用版本绑定重定向策略,也会在GAC和各个指定位置中进行查找。
4.LoadFrom()会直接返回Load()的结果,一个Assembly对象的引用。
5.如果目标程序集已经加载过,LoadFrom()不会重新进行加载。
6.LoadFrom支持从一个URL加载程序集(如"http://www.lpqmh.com/mt.dll"),这个程序集会被下载到用户缓存文件夹中。
7.从URL加载程序集时,如果计算机未联网,LoadFrom会抛出一个异常。如果IE被设置为“脱机工作”,则不会抛出异常,转而从缓存中寻找已下载的文件。

Assembly.LoadFile()

LoadFile从一个指定文件中加载程序集,它和LoadFrom不同之处在于,LoadFile不会加载目标程序集所引用和依赖的其它程序集,需要自己控制并显示加载所有依赖的程序集。

细节:
1.LoadFile不会解析任何依赖。
2.LoadFile可以多次加载同一程序集。
3.显示加载依赖程序集的方法是:在AppDomain中注册AssemblyResolve事件。

例如:
本文已Assembly.LoadFile为例加载“OpenCvSharp.dll”。
1.加载OpenCvSharp程序集

Assembly objType = Assembly.LoadFrom("OpenCvSharp.dll");

2.获取Mat类

Type MatType = objType.GetType("OpenCvSharp.Mat");

3.创建Mat对象
在创建对象前,需要先获取Grayscale

object Grayscale = null;
Type ImreadModesType = objType.GetType("OpenCvSharp.ImreadModes");
foreach (var f in ImreadModesType.GetFields(BindingFlags.Static | BindingFlags.Public))
            {
    
                if (f.Name == "Grayscale")
                {
    
                    Console.WriteLine($"Grayscale={
      f.Name}");
                    Console.WriteLine($"GrayscaleValue={
      f.GetValue(null)}");
                    Grayscale = f.GetValue(null);
                }
                Console.WriteLine(f.Name);
            }
object src = Activator.CreateInstance(MatType, new object[] {
    path, Grayscale });

4.获取泛型方法,如Get<T>(int i1, int i2)

MethodInfo m1 = MatType.GetMethod("Get", new Type[] {
     typeof(int), typeof(int)});
MethodInfo m2 = m1.MakeGenericMethod(new Type[] {
    typeof(byte)});
m2.Invoke(src, new object[]{
    i, j})

有方法重载时,需要使用Type[]数组传入参数类型。
获取如Set<T>(int i1, int i2, T vale)

MethodInfo ms = null;
            foreach(var f in src.GetType().GetMethods())
            {
    
                if (f.Name == "Set")
                {
    
                    
                    Console.WriteLine($"Name={
      f.Name}");
                    ParameterInfo[] parameterInfo = f.GetParameters();
                    Type[] typeArgements = f.GetGenericArguments();
                    for (int i = 0; i < parameterInfo.Length; ++i)
                    {
    
                        
                        Console.WriteLine("parameterInfo={0}", parameterInfo[i]);
                    }
                    foreach(Type tParam in typeArgements)
                    {
    
                        Console.WriteLine("tParam={0}", tParam);
                    }
                    if(parameterInfo.Length == 3)
                    {
    
                        ms = f;
                    }
                    
                    Console.WriteLine($"参数个数为:{
      parameterInfo.Length}");
                }
                    

            }
MethodInfo SetImg = ms;
MethodInfo ImgSet = SetImg.MakeGenericMethod(new Type[] {
     typeof(byte) });
ImgSet.Invoke(src, new Object[] {
     j, i, Convert.ToByte(0) });

Invoke方法中第一个参数为实例对象,若为静态方法则为null,第二个参数为传入的参数值。
5.获取类中的属性

int row = Convert.ToInt32(src.GetType().InvokeMember("Rows", BindingFlags.GetProperty, null, src, null));
int col = Convert.ToInt32(src.GetType().InvokeMember("Cols", BindingFlags.GetProperty, null, src, null));

其中src为实例对象。
6.获取方法

MethodInfo disMethod = src1.GetType().GetMethod("Dispose");
MethodInfo ChannelsMethod = src1.GetType().GetMethod("Channels");
int Channels = Convert.ToInt32(ChannelsMethod.Invoke(src1, null));

7.获取字段

Type MatTypeCV_8UC1 = objType.GetType("OpenCvSharp.MatType");
FieldInfo CV_8UC1 = MatTypeCV_8UC1.GetField("CV_8UC1", BindingFlags.Static | BindingFlags.Public);
CV_8UC1.GetValue(MatTypeCV_8UC1)
原网站

版权声明
本文为[草原上唱山歌]所创,转载请带上原文链接,感谢
https://blog.csdn.net/shanniuliqingming/article/details/126210229