使用assembly.getexecutingassembly().getmanifestresourcestream()读取嵌入资源时,需确保资源名格式为“默认命名空间.文件夹路径.文件名”,build action设为embedded resource,并用getmanifestresourcenames()调试验证;写入磁盘应选临时目录避免权限问题,注意进程占用和架构匹配,动态加载dll需手动处理解析逻辑与清理残留。

用 Assembly.GetExecutingAssembly().GetManifestResourceStream() 读取内嵌资源
项目里把 DLL 或 EXE 设为“嵌入的资源”(Build Action = Embedded Resource)后,它就变成程序集的一部分,不能直接当文件访问。得先用 GetManifestResourceStream() 拿到流——注意名字必须完全匹配,默认是 默认命名空间.文件夹路径.文件名,比如项目根命名空间是 MyApp,资源放在 Assets/tools/7z.exe,那资源名就是 MyApp.Assets.tools.7z.exe。
常见错误:资源名拼错、大小写不一致、没设对 Build Action、或忘了在属性窗口里把“复制到输出目录”关掉(它和嵌入资源互斥)。
- 用
Assembly.GetExecutingAssembly().GetManifestResourceNames()打印所有资源名,快速核对 - 调试时加个空检查:
if (stream == null) throw new InvalidOperationException($"资源未找到: {resourceName}");</li> <li>资源名中路径分隔符一律用英文点号 <code>.,不是斜杠
用 File.WriteAllBytes() 写入磁盘要处理路径和权限
拿到流之后,别直接用 StreamReader 或文本方式处理——二进制资源(如 EXE/DLL)必须原样写出,用 File.WriteAllBytes() 最稳妥。
目标路径选错会导致静默失败或权限拒绝。比如写到 C:\Program Files\ 下需要管理员权限,而用户临时目录(Path.GetTempPath())或当前程序目录(AppContext.BaseDirectory)更可靠。
- 优先写入
Path.Combine(Path.GetTempPath(), "mytool.exe"),避免权限问题 - 写之前用
Directory.CreateDirectory(Path.GetDirectoryName(destPath))确保父目录存在 - 写完建议调用
File.SetAttributes(destPath, FileAttributes.Hidden)防止被误删(可选)
释放前检查文件是否已存在且正在运行
重复释放同名 EXE 到同一位置,下次启动可能因文件被占用而失败——Windows 会锁住正在运行的 EXE 文件。
不能只靠 File.Exists(),得进一步判断该文件是否能被删除或重命名。一个轻量办法是尝试用 File.Move() 临时挪走再挪回,捕获 IOException。
- 更稳妥的做法:释放到带时间戳的唯一路径,例如
Path.Combine(tempDir, $"tool_{Guid.NewGuid():N}.exe") - 如果必须复用固定名,释放前先
Process.GetProcessesByName("tool")查是否有同名进程在跑 - 写入后建议用
Process.Start()启动,并立即调用process.WaitForExit(100)确认没卡住
释放 DLL 时要注意加载冲突和 AnyCPU 适配
释放的是依赖 DLL 而非主程序时,容易遇到 FileNotFoundException 或 BadImageFormatException。前者常因目标路径不在 AppDomain.CurrentDomain.AssemblyResolve 路径中;后者多因平台不匹配(比如 x64 程序试图加载 x86 DLL)。
不要指望写到 AppContext.BaseDirectory 就自动被加载——.NET Core/.NET 5+ 默认不从子目录加载,得手动注册解析逻辑。
- 若需动态加载,释放后用
Assembly.LoadFrom(destPath),而非LoadFile(后者不解决依赖链) - 提前用
System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture校验目标 DLL 架构是否匹配 - 对于插件式 DLL,建议统一放
plugins/子目录,并在启动时把该路径加入AssemblyLoadContext.Default.Resolving回调











