Assembly.Load按显示名称查找(GAC/已加载列表),LoadFrom按路径加载但复用同名程序集并解析依赖,LoadFile仅读取指定文件且不加载依赖。

别用 Assembly.LoadFrom 加载同名但路径不同的程序集,它会静默复用已加载的副本,导致类型不匹配、InvalidCastException 或方法找不到。
Assembly.Load、LoadFrom、LoadFile 三者行为差异在哪
它们不是“换种写法而已”,而是加载策略完全不同:
-
Assembly.Load:按显示名称(如"MyLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")查找并加载。走 GAC 或当前应用域已加载列表,失败时抛FileNotFoundException;适合已知强命名或系统/项目引用的程序集。 -
Assembly.LoadFrom:按文件路径加载,但会检查是否已有相同显示名称的程序集——有就直接返回那个,不管路径是否一致;同时会自动解析并加载其依赖项(递归加载)。这是最常用也最容易踩坑的方式。 -
Assembly.LoadFile:只读取指定路径的文件内容,完全不解析依赖;即使目标 DLL 引用了Newtonsoft.Json.dll,也不会自动加载它;调用时若缺失依赖,会在GetMethod或Invoke时才报FileNotFoundException,且错误堆栈不直观。
如何安全获取 Type 并创建实例
常见错误是直接用 Type.GetType("ClassName"),它只在当前程序集或 mscorlib 中查找,跨 DLL 必须带完整命名空间+程序集名:
- 正确写法:
assembly.GetType("MyNamespace.MyClass")—— 从已加载的Assembly实例中查,最可靠。 - 错误写法:
Type.GetType("MyNamespace.MyClass")—— 若该类不在当前执行程序集里,返回null,不报错,后续Activator.CreateInstance直接炸。 - 创建实例优先用
Activator.CreateInstance(type);若构造函数带参,确保传入的参数类型与GetConstructor获取的签名严格匹配(比如intvsInt32在反射里算不同)。
为什么 GetType() 返回 null 而不是抛异常
因为 Assembly.GetType(string) 的设计就是“查不到就返回 null”,不像 Assembly.GetTypes() 那样会把所有类型一次性加载并暴露可见性问题。容易忽略的点:
- 类必须是 public;internal 类即使在同一程序集内,用
GetType("...")也拿不到(除非用GetTypes().FirstOrDefault(t => t.Name == "...")+IsPublic判断)。 - 命名空间拼错、大小写不一致(C# 是大小写敏感的)、漏了嵌套层级(如
OuterClass+InnerClass写成OuterClass.InnerClass)都会导致null。 - Unity 用户注意:
Assembly-CSharp和Assembly-CSharp-Editor是两个独立程序集,不能混用GetType查找。
真正难调试的从来不是“怎么写”,而是“为什么没报错却得不到想要的类型”——多打一行 Console.WriteLine($"Loaded: {assembly.FullName}"); 和 Console.WriteLine($"All types: {string.Join(", ", assembly.GetTypes().Select(t => t.FullName))}");,比反复改 GetType 参数快得多。


















