美文网首页
2023-05-15 .Net反射程序集LoadFile、Loa

2023-05-15 .Net反射程序集LoadFile、Loa

作者: idengwei | 来源:发表于2023-05-15 00:47 被阅读0次

    0. 结论

    1. LoadFile必须使用绝对路径,LoadFrom可以用绝对路径和相对路径
    2. LoadFile不会加载程序集所引用和依赖的其他程序集
    3. (未验证)LoadFrom载入前会检查是否已载入同名程序集,如果同一上下文中已载入不会重复载入/当作“数据文件”载入,即使版本不同
    4. 不同上下文可载入同名程序集,且会被视作不同类型

    1. 示例1

    • TestA 为底层库;
    • TestB 引用 TestA;
    • TestC 反射加载 TestB,TestB 与 TestC 不在同一路径。

    1) LoadFile: TestC 通过 LoadFile 加载 TestB

    LoadFile 必须使用绝对路径,否则会产生异常(需要绝对路径信息);

    TestA 与 TestC 在同一路径:LoadFile("TestB.dll") 正常,执行引用TestA的方法MethodInfo.Invoke()正常;
    TestA 与 TestC 不在同一路径:LoadFile("TestB.dll") 正常,执行引用TestA的方法MethodInfo.Invoke()异常(找不到TestA文件)。
    

    2) LoadFrom: TestC 通过 LoadFrom 加载 TestB

    LoadFrom 可以用绝对路径,也可以用相对路径;

    TestA 与 TestC 在同一路径:LoadFile("TestB.dll") 正常,执行引用TestA的方法MethodInfo.Invoke()正常;
    TestA 与 TestB 在同一路径:LoadFile("TestB.dll") 正常,执行引用TestA的方法MethodInfo.Invoke()正常;
    TestA 与 TestC, TestB 均不在同一路径:LoadFile("TestB.dll") 正常,执行引用TestA的方法MethodInfo.Invoke()异常(找不到TestA文件)。
    

    3) 重复LoadFrom: TestC 通过 LoadFrom 先加载 TestA,再加载TestB

    // TestC静态引用TestA,TestB静态引用TestA,TestA2为TestA副本
    
    // 以下代码AppDomain.CurrentDomain.GetAssemblies()结果:
    // TestC;
    // TestA;
    // SubDir\TestB.dll;
    LoadFrom(@".\SubDir\TestB.dll"); // 不重复加载已静态引用的TestA
    
    // 以下代码AppDomain.CurrentDomain.GetAssemblies()结果:
    // TestC;
    // TestA;
    // SubDir\TestA.dll;
    // SubDir\TestB.dll;
    LoadFrom(@".\SubDir\TestA.dll"); // 重复加载TestA
    LoadFrom(@".\SubDir\TestB.dll"); 
    
    // 以下代码AppDomain.CurrentDomain.GetAssemblies()结果:
    // TestC;
    // TestA;
    // SubDir\TestA.dll;
    // SubDir\TestB.dll;
    LoadFrom(@".\SubDir\TestA.dll");
    LoadFrom(@".\SubDir\TestB.dll");
    LoadFrom(@".\SubDir\TestA2.dll"); // 不重复加载已加载的TestA
    

    重复加载导致的类型匹配问题
    顺序有关,先LoadFrom,则不可以,否则可以
    在确定一个类型是否可强制转换为另一个类型时,路径很重要。即使包含类型的程序集相同,如果它们从不同的路径加载,它们也被视为不同的程序集,因此它们的类型也不同。这就是为什么使用加载上下文以外的上下文存在风险的原因之一。您可能会遇到以下情况:同一程序集在同一 appdomain 中多次加载(一次在 Load 上下文中,一次在 LoadFrom 上下文中,甚至两次在两个上下文中加载多次),并且它们的相应类型不可强制转换。

    4) 类型(接口、特性)匹配查找问题

    // 以下代码AppDomain.CurrentDomain.GetAssemblies()结果:
    // TestC;
    // TestA;
    // SubDir\TestA.dll;
    // SubDir\TestB.dll;
    LoadFrom(@".\SubDir\TestA.dll"); 
    LoadFrom(@".\SubDir\TestB.dll");
    // 此时通过BaseType(GetCustomAttributes、GetInterfaces)从TestB中获取的TestA中类型(接口、特性) != 从TestC中获取的TestA中类型(接口、特性):
    Console.WriteLine(type.BaseType == typeof(TestA.TestA)); // False
    Console.WriteLine(type.GetInterface("TestA .ITestA") == typeof(TestA.ITestA)); // False
    Console.WriteLine(type.GetCustomAttributes(typeof(TestA .TestAAttrubute), true) == typeof(TestA.TestAAttrubute)); // TestA.TestAAttrubute[0]
    
    // 以下代码AppDomain.CurrentDomain.GetAssemblies()结果:
    // TestC;
    // TestA;
    // SubDir\TestB.dll;
    LoadFrom(@".\SubDir\TestB.dll");
    // 此时通过BaseType(GetCustomAttributes、GetInterfaces)从TestB中获取的TestA中类型(接口、特性) != 从TestC中获取的TestA中类型(接口、特性):
    Console.WriteLine(type.BaseType == typeof(TestA.TestA)); // True
    Console.WriteLine(type.GetInterface("TestA .ITestA") == typeof(TestA.ITestA)); // True
    Console.WriteLine(type.GetCustomAttributes(typeof(TestA .TestAAttrubute), true) == typeof(TestA.TestAAttrubute)); // TestA.TestAAttrubute[1]
    

    2. 示例2

    // path1 and path2 point to different copies of the same assembly on disk:
    
    Assembly assembly1 = Assembly.LoadFrom(path1);
    Assembly assembly2 = Assembly.LoadFrom(path2);
    
    // These both point to the assembly from path1, so this is true
    Console.WriteLine(assembly1.CodeBase == assembly2.CodeBase);
    
    assembly1 = Assembly.LoadFile(path1);
    assembly2 = Assembly.LoadFile(path2);
    
    // These point to different assemblies now, so this is false
    Console.WriteLine(assembly1.CodeBase == assembly2.CodeBase);
    

    3. 参考

    C#反射-Assembly.Load、LoadFrom与LoadFile进阶 - zagelover - 博客园 (cnblogs.com)
    C#反射-Assembly.Load、LoadFrom与LoadFile详细例子用法_c# assembly.loadfrom相对路径
    使用.NET程序集的LoadFile和LoadFrom之间的区别? - 问答 - 腾讯云开发者社区-腾讯云 (tencent.com)
    Suzanne Cook's .NET CLR Notes | Microsoft Learn
    Choosing a Binding Context | Microsoft Learn
    C#加载程序集 - 掘金 (juejin.cn)

    相关文章

      网友评论

          本文标题:2023-05-15 .Net反射程序集LoadFile、Loa

          本文链接:https://www.haomeiwen.com/subject/oiopsdtx.html