Assembly resolve(自定义加载指定目录的程序集)

本文介绍如何利用AssemblyResolve事件处理程序,避免将大量DLL放置在主程序目录下造成混乱。通过指定目录加载dll文件,实现程序集的自定义加载。

 默认情况下项目引用的dll都需要放在跟主程序相同的目录下,当项目引用的dll越来越多,则会显得凌乱。

这时可以通过AssemblyResolve来处理这件事情。


AppDomain.CurrentDomain.AssemblyResolve += OnCurrentDomainAssemblyResolve;
private Assembly OnCurrentDomainAssemblyResolve(object sender, ResolveEventArgs args)
{
if(string.IsNullOrWhiteSpace(args.Name))
{
return null;
}

string[] assemblyNameSplits = args.Name.Split(',');
if(assemblyNameSplits.Length == 0)
{
return null;
}

string name = asemblyNameSplits[0];
if(asemblyNameSplits.Length==3)
{
string name2= asemblyNameSplits[2];
if(name.EndsWith(".resources") && name2.EndsWith("neutral"))
{
return null;
}
else
{
return LoadAssembly(name);
}

}

return LoadAssembly(name);

}

private Assembly LoadAssembly(string name)
{
if(assemblyLoadedDic.ContainsKey(name))
{
return assemblyLoadedDic[name];
}
else
{
if(assemblyPathsDic.ContainsKey(name))
{
string path = assemblyPathsDic[name].AssemblyPath;
Assembly loadedAssembly = Assembly.LoadFile(path);
assemblyLoadedDic[name] = loadedAssembly;
return loadedAssembly;
}

}
return null;
}



根据一个目录,读取目录及子目录下所有dll

private Dictonary<string,AssemblyItem> GetAssemblyPaths(string folderPath)
{
string folder = folderPath;
if(!Path.IsPathRooted(folderPath))
{
folder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,folder);
<span style="font-family: Arial, Helvetica, sans-serif;">}</span>

</pre><pre name="code" class="csharp">if(!Directory.Exists(forder))
{
return null;
}
</pre><pre name="code" class="csharp">var result = new Dictonary<string,AssemblyItem>();
</pre><pre name="code" class="csharp">string dllfiles = Direcotry.GetFiles(folder,"*.dll",SearchOption.AllDirecotries);
foreach(var dllfile in dllfiles)
{
string assemblyname = Path.GetFileName(dllfile);
assemblyname = assemblyname.Substring(0,assemblyname.Length - 4);
string assemblyPath = Path.GetFullPath(dllfile);
</pre><pre name="code" class="csharp">var assemblyItem = new AssemblyItem()
{
AssemblyName = assemblyname,
AssemblyPaht = assemblyPath,
};
</pre><pre name="code" class="csharp">result[assemblyname] = assemblyItem;

</pre><pre name="code" class="csharp">}
</pre><pre name="code" class="csharp">return resutl;
</pre><pre name="code" class="csharp">}


<think>我们正在处理一个关于Mono.Cecil的异常问题,具体是AssemblyResolutionException,提示无法解析程序集'F8Framework.Launcher, Version=0.0.0.0'。这通常发生在使用Mono.Cecil读取或修改程序集时,它无法找到所需的依赖项。 ### 问题分析 1. **异常原因**:Mono.Cecil在解析目标程序集(这里是`Assembly-CSharp.dll`)时,发现它引用了`F8Framework.Launcher`程序集,但该程序集不在Mono.Cecil的搜索路径中。 2. **可能情况**: - `F8Framework.Launcher.dll`确实不存在于当前工作目录指定的搜索路径中。 - 版本不匹配:虽然存在该程序集,但版本号不是0.0.0.0(通常0.0.0.0表示未指定版本,但可能实际需要的是特定版本)。 - 程序集名称不一致:例如,程序集文件名可能不是`F8Framework.Launcher.dll`,或者程序集的全名(包括公钥标记等)不匹配。 ### 解决方案 #### 方法1:确保程序集在正确的目录中 - 将`F8Framework.Launcher.dll`复制到Mono.Cecil正在搜索的目录中。通常,这是应用程序的工作目录,或者你可以通过设置`AssemblyResolver`来指定额外的搜索路径。 #### 方法2:自定义解析器(推荐) Mono.Cecil允许你自定义程序集解析器(`IAssemblyResolver`)。你可以实现一个解析器,在找不到程序集时提供自定义逻辑。 以下是一个示例,展示如何实现一个简单的解析器,将程序集名称映射到文件路径: ```csharp using Mono.Cecil; using System.IO; public class CustomAssemblyResolver : DefaultAssemblyResolver { // 添加一个搜索目录 public void AddSearchDirectory(string directory) { base.AddSearchDirectory(directory); } } // 使用自定义解析器 var resolver = new CustomAssemblyResolver(); resolver.AddSearchDirectory("path/to/your/assemblies"); // 添加包含F8Framework.Launcher.dll的目录 var parameters = new ReaderParameters { AssemblyResolver = resolver }; // 读取目标程序集 var assembly = AssemblyDefinition.ReadAssembly("path/to/Assembly-CSharp.dll", parameters); ``` #### 方法3:忽略版本号(如果适用) 如果你不关心版本号,可以在解析时忽略版本检查。这可以通过在自定义解析器中重写`Resolve`方法来实现: ```csharp public class IgnoreVersionResolver : DefaultAssemblyResolver { public override AssemblyDefinition Resolve(AssemblyNameReference name) { // 尝试忽略版本号进行解析 name = new AssemblyNameReference(name.Name, new Version(0,0,0,0)); return base.Resolve(name); } } ``` 注意:这种方法可能会引起兼容性问题,所以请确保程序集版本兼容。 #### 方法4:检查程序集引用 如果`F8Framework.Launcher`是用户自己的程序集,检查其是否被正确生成并放置在输出目录中。如果是第三方程序集,确保已正确安装。 ### 其他注意事项 - **Unity项目**:如果是在Unity环境中,确保`F8Framework.Launcher.dll`位于`Assets`文件夹下的某个位置(例如`Assets/Plugins`),并且其平台设置正确。 - **版本0.0.0.0**:在Unity中,有时会生成版本号为0.0.0.0的程序集。确保你的解析器能够处理这种情况。 ### 相关问题 1. 如何调试Mono.Cecil的程序集解析过程? 2. 在Unity中使用Mono.Cecil有哪些最佳实践? 3. 如何处理程序集引用中的强命名程序集? 通过上述方法,你应该能够解决这个程序集解析失败的问题。如果问题仍然存在,请检查程序集是否损坏或是否存在其他依赖问题。 [^1]: Mono.Cecil官方文档:https://www.mono-project.com/docs/tools+libraries/libraries/Mono.Cecil/</think>### 解决 Mono.Cecil 程序集解析失败的方法 当遇到 `Mono.Cecil.AssemblyResolutionException: Failed to resolve assembly 'F8Framework.Launcher'` 异常时,通常是因为 Mono.Cecil 无法找到所需的依赖程序集。以下是系统化的解决方案: #### 1. **添加自定义解析器(核心方案)** ```csharp using Mono.Cecil; using System.IO; // 实现自定义程序集解析器 public class CustomAssemblyResolver : IAssemblyResolver { public AssemblyDefinition Resolve(AssemblyNameReference name) { // 特殊处理目标程序集 if (name.Name == "F8Framework.Launcher") { string path = Path.Combine( Application.dataPath, "Plugins/F8Framework.Launcher.dll" ); return AssemblyDefinition.ReadAssembly(path); } // 其他程序集使用默认解析 return DefaultAssemblyResolver.Instance.Resolve(name); } } // 使用解析器读取程序集 var readerParams = new ReaderParameters { AssemblyResolver = new CustomAssemblyResolver() // 注入自定义解析器 }; var assembly = AssemblyDefinition.ReadAssembly("Assembly-CSharp.dll", readerParams); ``` **关键点**: - 通过 `IAssemblyResolver` 接口实现自定义解析逻辑 - 显式指定缺失程序集的物理路径 - 需要确保路径中的 `.dll` 文件实际存在 #### 2. **验证程序集物理位置** 检查以下位置是否存在目标文件: ```bash # Unity 项目常见路径 ./Assets/Plugins/F8Framework.Launcher.dll ./Library/ScriptAssemblies/F8Framework.Launcher.dll ./Packages/manifest.json # 检查包依赖 ``` #### 3. **处理版本不匹配问题** 如果版本冲突(如 `Version=0.0.0.0`): ```csharp // 在自定义解析器中添加版本忽略 if (name.Name == "F8Framework.Launcher") { var asmDef = AssemblyDefinition.ReadAssembly(path); asmDef.Name.Version = name.Version; // 强制匹配请求版本 return asmDef; } ``` #### 4. **依赖项检查(预防措施)** 使用 ILSpy 或 dnSpy 检查依赖树: ```bash # 通过命令行工具检查引用 ildasm Assembly-CSharp.dll /output=refs.txt ``` 在输出文件中搜索 `.assembly extern F8Framework.Launcher` 确认引用声明[^1]。 #### 5. **Unity 特定解决方案** 如果是 Unity 项目: 1. 在 Player Settings 中开启 **Allow 'unsafe' Code** 2. 确保目标程序集在 Assets 目录中有 `.meta` 文件 3. 执行菜单操作: *Assets > Reimport All* ### 根本原因分析 此异常通常由以下原因触发: 1. 程序集未包含在编译输出目录 2. 版本号不匹配(如强签名程序集) 3. 动态加载上下文未正确配置 4. Unity 的 JIT 编译限制导致元数据缺失 ### 相关问题 1. 如何调试 Mono.Cecil 的 AssemblyResolutionException 详细堆栈? 2. 在 Unity IL2CPP 模式下使用 Mono.Cecil 需要注意哪些特殊限制? 3. 如何强制 Mono.Cecil 跳过特定程序集的验证? 4. 除了自定义解析器,还有哪些处理缺失程序集的替代方案? [^1]: Mono.Cecil 官方文档建议始终通过自定义解析器处理依赖关系,特别是在动态加载场景中。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr蹇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值