一、简介
很长时间没有关注一些C#技术细节了,主要在研究微服务、容器、云原生、容器编排等高大上的主题了,最近在写一些框架的时候,遇到了一些和在 Net Framework 框架下不一样的情况,当然了,我今天主要测试的是,在通过【添加项目引用】和【手动拷贝DLL】的情况下,这三个方法加载程序集:Assembly.Load()、Assmebly.LoadFile() 和Assembly.LoadFrom() 的区别,别的可没测试,今天就把我的测试过程发布出来,如果对大家有帮助,我当然很高兴,如果是高手,也希望不吝赐教。
测试环境:
操作系统:Windows 10 Professional
开发工具:Visual Studio 2022
测试平台:Window Form
DotNet版本:Net 7.0
二、测试过程
最近,我在写一些底层框架,需要用到反射,项目要做到热拔插、热启动等类似的功能,有人说 Assembly.Load() 可以直接输入程序集的名称就可以加载拷贝到当前运行目录下的程序集,我一运行,就出现了错误,索性,我就都测试一下,所以就有了今天的测试。在编码的过程中出现了一些和预期不一样的地方,我就把测试的代码发布出来,也希望大家提出宝贵的意见。
直接上代码,然后再总结,今天主要测试 Assembly.Load()、Assmebly.LoadFile() 和Assembly.LoadFrom() 的区别,当然只是一家之言,也有疏忽之处,也希望大家批评指正。
代码如下:
1 //202309181033、通过多种方法加载程序集 2 { 3 //可以是程序集全名,也可以文件名,必须引用项目,拷贝到目录下无效 4 5 //1.1、Load加载(没有引用项目,直接将 DLL 拷贝到程序运行目录下) 6 { 7 //[1]、使用强命名的程序集名称,报错【Could not load file or assembly 'PatrickLiu.Database.SqlServer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. 系统找不到指定的文件。】 8 Assembly assembly = Assembly.Load("PatrickLiu.Database.SqlServer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"); 9 10 //[2]、使用程序集弱命名,包含后缀名,报错【Could not load file or assembly 'PatrickLiu.Database.SqlServer.dll, Culture=neutral, PublicKeyToken=null'. 系统找不到指定的文件。】 11 Assembly assembly2 = Assembly.Load("PatrickLiu.Database.SqlServer.dll"); 12 13 //[3]、完整路径,程序集名称,包含后缀名,也报错【The given assembly name was invalid.】 14 Assembly assembly22 = Assembly.Load("E:\\Visual Studio 2022\\Source\\Projects\\PatrickLiu.DelegateDeep.Study\\PatrickLiu.DelegateDeep.AllStudy\\bin\\Debug\\net7.0\\PatrickLiu.Database.SqlServer.dll"); 15 16 //[4]、完整路径,程序集名称,不包含后缀名,报错【The given assembly name was invalid.】 17 Assembly assembly23 = Assembly.Load("E:\\Visual Studio 2022\\Source\\Projects\\PatrickLiu.DelegateDeep.Study\\PatrickLiu.DelegateDeep.AllStudy\\bin\\Debug\\net7.0\\PatrickLiu.Database.SqlServer"); 18 19 //[5]、程序集弱名称名称,不包含后缀名,报错【Could not load file or assembly 'PatrickLiu.Database.SqlServer, Culture=neutral, PublicKeyToken=null'. 系统找不到指定的文件。】 20 Assembly assembly24 = Assembly.Load("PatrickLiu.Database.SqlServer"); 21 22 //[6]、通过 File 读取字节数据,包含程序集名称和文件后缀名,正常加载---VVVVVVV。 23 Assembly assembly25 = Assembly.Load(File.ReadAllBytes("PatrickLiu.Database.SqlServer.dll")); 24 25 //[7]、通过 File 读取字节数据,包含程序集名称,不包含文件后缀名,报错【Could not find file 'E:\Visual Studio 2022\Source\Projects\PatrickLiu.DelegateDeep.Study\PatrickLiu.DelegateDeep.AllStudy\bin\Debug\net7.0\PatrickLiu.Database.SqlServer'.】。 26 //Assembly assembly26 = Assembly.Load(File.ReadAllBytes("PatrickLiu.Database.SqlServer")); 27 28 //[8]、通过 File 读取字节数据,包含程序集完整路径和文件后缀名,正常加载---VVVVVVV。 29 Assembly assembly27 = Assembly.Load(File.ReadAllBytes("E:\\Visual Studio 2022\\Source\\Projects\\PatrickLiu.DelegateDeep.Study\\PatrickLiu.DelegateDeep.AllStudy\\bin\\Debug\\net7.0\\PatrickLiu.Database.SqlServer.dll")); 30 31 //[9]、通过 File 读取字节数据,包含程序集完整路径,不包含文件后缀名,报错【Could not find file 'E:\Visual Studio 2022\Source\Projects\PatrickLiu.DelegateDeep.Study\PatrickLiu.DelegateDeep.AllStudy\bin\Debug\net7.0\PatrickLiu.Database.SqlServer'.】。 32 Assembly assembly28 = Assembly.Load(File.ReadAllBytes("E:\\Visual Studio 2022\\Source\\Projects\\PatrickLiu.DelegateDeep.Study\\PatrickLiu.DelegateDeep.AllStudy\\bin\\Debug\\net7.0\\PatrickLiu.Database.SqlServer")); 33 } 34 35 //1.2、Load加载(直接引用项目,系统自己会拷贝,没有人为拷贝 DLL 到目录下) 36 { 37 //[1]、使用强命名的程序集名称,正常加载---VVVVVVV。 38 Assembly assembly = Assembly.Load("PatrickLiu.Database.SqlServer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"); 39 40 //[2]、使用程序集弱命名,正常加载---VVVVVVV。 41 Assembly assembly2 = Assembly.Load("PatrickLiu.Database.SqlServer"); 42 43 //[3]、完整路径,程序集名称和后缀名,也报错【The given assembly name was invalid.】 44 Assembly assembly22 = Assembly.Load("E:\\Visual Studio 2022\\Source\\Projects\\PatrickLiu.DelegateDeep.Study\\PatrickLiu.DelegateDeep.AllStudy\\bin\\Debug\\net7.0\\PatrickLiu.Database.SqlServer.dll"); 45 46 //[4]、完整路径,程序集名称,不包含后缀名,报错【The given assembly name was invalid.】 47 Assembly assembly23 = Assembly.Load("E:\\Visual Studio 2022\\Source\\Projects\\PatrickLiu.DelegateDeep.Study\\PatrickLiu.DelegateDeep.AllStudy\\bin\\Debug\\net7.0\\PatrickLiu.Database.SqlServer"); 48 49 //[5]、程序集弱名称名称,包含文件扩展名,报错【Could not load file or assembly 'PatrickLiu.Database.SqlServer, Culture=neutral, PublicKeyToken=null'. 系统找不到指定的文件。】 50 Assembly assembly24 = Assembly.Load("PatrickLiu.Database.SqlServer.dll"); 51 52 //[6]、通过 File 读取字节数据,包含程序集后缀名,正常加载---VVVVVVV。 53 Assembly assembly25 = Assembly.Load(File.ReadAllBytes("PatrickLiu.Database.SqlServer.dll")); 54 55 //[7]、通过 File 读取字节数据,不包含程序集后缀名,报错【Could not find file 'E:\Visual Studio 2022\Source\Projects\PatrickLiu.DelegateDeep.Study\PatrickLiu.DelegateDeep.AllStudy\bin\Debug\net7.0\PatrickLiu.Database.SqlServer'】。 56 Assembly assembly26 = Assembly.Load(File.ReadAllBytes("PatrickLiu.Database.SqlServer")); 57 58 //[8]、通过 File 读取字节数据,包含程序集完整路径和文件后缀名,正常加载---VVVVVVV。 59 Assembly assembly27 = Assembly.Load(File.ReadAllBytes("E:\\Visual Studio 2022\\Source\\Projects\\PatrickLiu.DelegateDeep.Study\\PatrickLiu.DelegateDeep.AllStudy\\bin\\Debug\\net7.0\\PatrickLiu.Database.SqlServer.dll")); 60 61 //[9]、通过 File 读取字节数据,包含程序集完整路径,不包含文件后缀名,报错【Could not find file 'E:\Visual Studio 2022\Source\Projects\PatrickLiu.DelegateDeep.Study\PatrickLiu.DelegateDeep.AllStudy\bin\Debug\net7.0\PatrickLiu.Database.SqlServer'.】。 62 Assembly assembly28 = Assembly.Load(File.ReadAllBytes("E:\\Visual Studio 2022\\Source\\Projects\\PatrickLiu.DelegateDeep.Study\\PatrickLiu.DelegateDeep.AllStudy\\bin\\Debug\\net7.0\\PatrickLiu.Database.SqlServer")); 63 } 64 65 //总结: 66 //Assembly.Load()针对【添加项目引用】和【通过手动拷贝】来加载程序集是有区别的,如果通过 Visual Studio IDE 【添加项目引用】菜单引用了程序集,只要书写正确,都能正常加载程序集,支持【强命名程序集】加载和【弱命名程序集】加载,如果加载的是弱命名的程序集不要写程序集的后缀名(.dll),不需要书写程序集的完整或者相对路径。Assembly.Load(File.ReadAllBytes())这个方法参数可以接受:必须包含后缀名的程序集名称或者包含完整路径、并包含后缀名的程序集名称,形如:Assembly.Load(File.ReadAllBytes("XXX.dll(包含后缀名的程序集名称)")),Assembly.Load(File.ReadAllBytes("E:\\XX\\XXX\\XXXX\\PatrickLiu.Database.SqlServer.dll(包含完整路径、并包含后缀名的程序集名称)"))这两种方式都是有效的。如果在不引用程序集(是不通过VS菜单【添加项目引用】),还想使用 Assembly.Load() 方法成功加载程序集,只能通过 Assembly.Load(File.ReadAllBytes())这种方式,当然我只测试了这个接口,其他的大家可以尝试。 67 68 //2、LoadFile加载(必须是完整路径,包含扩展名,不用引用项目,拷贝到目录就可以) 69 70 //2.1、LoadFile()在不引用程序集,通过拷贝DLL到指定目录来执行 71 { 72 //[1]、只包含程序集的名称和文件扩展名,报错【Path "PatrickLiu.Database.SqlServer.dll" is not an absolute path. 】 73 Assembly assembly221 = Assembly.LoadFile("PatrickLiu.Database.SqlServer.dll"); 74 75 //[2]、包含程序集完整路径,程序集名称和文件扩展名,正常加载--------VVVVVV。 76 Assembly assembly222 = Assembly.LoadFile("E:\\Visual Studio 2022\\Source\\Projects\\PatrickLiu.DelegateDeep.Study\\PatrickLiu.DelegateDeep.AllStudy\\bin\\Debug\\net7.0\\PatrickLiu.Database.SqlServer.dll"); 77 78 //[3]、只包含程序集的名称,报错【Path "PatrickLiu.Database.SqlServer" is not an absolute path】 79 Assembly assembly223 = Assembly.LoadFile("PatrickLiu.Database.SqlServer"); 80 81 //[3]、报错【Could not load file or assembly 'E:\Visual Studio 2022\Source\Projects\PatrickLiu.DelegateDeep.Study\PatrickLiu.DelegateDeep.AllStudy\bin\Debug\net7.0\PatrickLiu.Database.SqlServer'. The system cannot find the file specified.”】 82 Assembly assembly224 = Assembly.LoadFile("E:\\Visual Studio 2022\\Source\\Projects\\PatrickLiu.DelegateDeep.Study\\PatrickLiu.DelegateDeep.AllStudy\\bin\\Debug\\net7.0\\PatrickLiu.Database.SqlServer"); 83 } 84 //2.2、LoadFile()在引用程序集 85 { 86 //[1]、只包含程序集的名称和文件扩展名,报错【Path "PatrickLiu.Database.SqlServer.dll" is not an absolute path. 】 87 Assembly assembly221 = Assembly.LoadFile("PatrickLiu.Database.SqlServer.dll"); 88 89 //[2]、包含程序集完整路径,程序集名称和文件扩展名,正常加载--------VVVVVV。 90 Assembly assembly222 = Assembly.LoadFile("E:\\Visual Studio 2022\\Source\\Projects\\PatrickLiu.DelegateDeep.Study\\PatrickLiu.DelegateDeep.AllStudy\\bin\\Debug\\net7.0\\PatrickLiu.Database.SqlServer.dll"); 91 92 //[3]、只包含程序集的名称,报错【Path "PatrickLiu.Database.SqlServer" is not an absolute path】 93 Assembly assembly223 = Assembly.LoadFile("PatrickLiu.Database.SqlServer"); 94 95 //[3]、报错【Could not load file or assembly 'E:\Visual Studio 2022\Source\Projects\PatrickLiu.DelegateDeep.Study\PatrickLiu.DelegateDeep.AllStudy\bin\Debug\net7.0\PatrickLiu.Database.SqlServer'. The system cannot find the file specified.”】 96 Assembly assembly224 = Assembly.LoadFile("E:\\Visual Studio 2022\\Source\\Projects\\PatrickLiu.DelegateDeep.Study\\PatrickLiu.DelegateDeep.AllStudy\\bin\\Debug\\net7.0\\PatrickLiu.Database.SqlServer"); 97 } 98 99 //总结:Assembly.LoadFile()方法使用也比较简单,无论是在【添加项目引用】还是【手动拷贝】都可以正常加载程序集,唯一要注意的就是,必须书写完整的程序集路径,程序集文件名,也包含扩展名。 100 101 102 //3、LoadFrom加载(程序集全名不可以,文件名也不可以,原因不知道,文件全名可以,不用引用项目,直接拷贝就可以) 103 //必须增加后缀名 104 105 //3.1、不引用项目,把所需的Dll 拷贝到目标目录下 106 { 107 108 //[1]、使用强命名的程序集名称,正常加载---VVVVVVV。 109 Assembly assembly31 = Assembly.LoadFrom("PatrickLiu.Database.SqlServer.dll"); 110 111 //[2]、使用强命名的程序集名称,报错【Could not load file or assembly 'E:\Visual Studio 2022\Source\Projects\PatrickLiu.DelegateDeep.Study\PatrickLiu.DelegateDeep.AllStudy\bin\Debug\net7.0\PatrickLiu.Database.SqlServer'. 系统找不到指定的文件。”】。 112 Assembly assembly32 = Assembly.LoadFrom("PatrickLiu.Database.SqlServer"); 113 114 //[3]、完成的程序集路径,程序集名称,程序集扩展名,正常加载---VVVVVVV。 115 Assembly assembly33 = Assembly.LoadFrom("E:\\Visual Studio 2022\\Source\\Projects\\PatrickLiu.DelegateDeep.Study\\PatrickLiu.DelegateDeep.AllStudy\\bin\\Debug\\net7.0\\PatrickLiu.Database.SqlServer.dll"); 116 117 //[4]、完成的程序集路径,程序集名称,程序集扩展名,报错【Could not load file or assembly 'E:\Visual Studio 2022\Source\Projects\PatrickLiu.DelegateDeep.Study\PatrickLiu.DelegateDeep.AllStudy\bin\Debug\net7.0\PatrickLiu.Database.SqlServer'. 系统找不到指定的文件。】。 118 Assembly assembly34 = Assembly.LoadFrom("E:\\Visual Studio 2022\\Source\\Projects\\PatrickLiu.DelegateDeep.Study\\PatrickLiu.DelegateDeep.AllStudy\\bin\\Debug\\net7.0\\PatrickLiu.Database.SqlServer"); 119 } 120 121 //3.2、引用项目,系统将 Dll 拷贝到目标目录下 122 { 123 //[1]、使用强命名的程序集名称,正常加载---VVVVVVV。 124 Assembly assembly31 = Assembly.LoadFrom("PatrickLiu.Database.SqlServer.dll"); 125 126 //[2]、使用强命名的程序集名称,报错【Could not load file or assembly 'E:\Visual Studio 2022\Source\Projects\PatrickLiu.DelegateDeep.Study\PatrickLiu.DelegateDeep.AllStudy\bin\Debug\net7.0\PatrickLiu.Database.SqlServer'. 系统找不到指定的文件。”】。 127 Assembly assembly32 = Assembly.LoadFrom("PatrickLiu.Database.SqlServer"); 128 129 //[3]、完成的程序集路径,程序集名称,程序集扩展名,正常加载---VVVVVVV。 130 Assembly assembly33 = Assembly.LoadFrom("E:\\Visual Studio 2022\\Source\\Projects\\PatrickLiu.DelegateDeep.Study\\PatrickLiu.DelegateDeep.AllStudy\\bin\\Debug\\net7.0\\PatrickLiu.Database.SqlServer.dll"); 131 132 //[4]、完成的程序集路径,程序集名称,程序集扩展名,报错【Could not load file or assembly 'E:\Visual Studio 2022\Source\Projects\PatrickLiu.DelegateDeep.Study\PatrickLiu.DelegateDeep.AllStudy\bin\Debug\net7.0\PatrickLiu.Database.SqlServer'. 系统找不到指定的文件。】。 133 Assembly assembly34 = Assembly.LoadFrom("E:\\Visual Studio 2022\\Source\\Projects\\PatrickLiu.DelegateDeep.Study\\PatrickLiu.DelegateDeep.AllStudy\\bin\\Debug\\net7.0\\PatrickLiu.Database.SqlServer"); 134 } 135 136 总结:Assembly.LoadFrom()使用起来相对简单一点,无论是在已经【添加项目引用】还是【手动拷贝】都可以正常加载程序集,但是方法的参数必须是:(1)、包含完整路径、程序集名称和后缀名的程序集,如:Assembly.LoadFrom("E:\\X\\XX\\XXX\\PatrickLiu.Database.SqlServer.dll"),(2)、参数必须包含程序集名称和后缀名,如:Assembly.LoadFrom("PatrickLiu.Database.SqlServer.dll") 137 }
1、Assembly.Load()针对【添加项目引用】和【通过手动拷贝】来加载程序集是有区别的,如果通过 Visual Studio IDE 【添加项目引用】菜单引用了程序集,只要书写正确,都能正常加载程序集,支持【强命名程序集】加载和【弱命名程序集】加载,如果加载的是弱命名的程序集不要写程序集的后缀名(.dll),不需要书写程序集的完整或者相对路径。Assembly.Load(File.ReadAllBytes())这个方法参数可以接受:必须包含后缀名的程序集名称或者包含完整路径、并包含后缀名的程序集名称,形如:Assembly.Load(File.ReadAllBytes("XXX.dll(包含后缀名的程序集名称)")),Assembly.Load(File.ReadAllBytes("E:\\XX\\XXX\\XXXX\\PatrickLiu.Database.SqlServer.dll(包含完整路径、并包含后缀名的程序集名称)"))这两种方式都是有效的。如果在不引用程序集(是不通过VS菜单【添加项目引用】),还想使用 Assembly.Load() 方法成功加载程序集,只能通过 Assembly.Load(File.ReadAllBytes())这种方式,当然我只测试了这个接口,其他的大家可以尝试。
2、Assembly.LoadFile()方法使用也比较简单,无论是在【添加项目引用】还是【手动拷贝】都可以正常加载程序集,唯一要注意的就是,必须书写完整的程序集路径,程序集文件名,也包含扩展名,如:Assembly.LoadFile("E:\\X\\XX\\XXX\\PatrickLiu.Database.SqlServer.dll")。
3、Assembly.LoadFrom()使用起来相对简单一点,无论是在已经【添加项目引用】还是【手动拷贝】都可以正常加载程序集,但是方法的参数必须是:(1)、包含完整路径、程序集名称和后缀名的程序集,如:Assembly.LoadFrom("E:\\X\\XX\\XXX\\PatrickLiu.Database.SqlServer.dll"),(2)、参数必须包含程序集名称和后缀名,如:Assembly.LoadFrom("PatrickLiu.Database.SqlServer.dll")
三、总结
好了,今天就写道这里了,总算还不错,能有点收获。如果以后有新的需求,在测试把。每天进步一点点,努力一直在路上。