.NET Framework 4.8加载资源时遇System.IO.FileNotFoundException求助
问题背景
维护基于.NET Framework 4.8的遗留C# WinForms项目,使用Visual Studio一键发布后在其他电脑出现System.IO.FileNotFoundException,后续本地调试也触发相同错误。错误根源在InitializeComponent中的这段代码:
this.imlProcesses.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imlProcesses.ImageStream")));
通过System.ComponentModel.ComponentResourceManager加载frmMain资源时,错误提示找不到PixyControl.resources,但经DotPeek确认,项目已正确嵌入EA.PixyControl.frmMain.resources资源。尝试还原.resx文件属性(Build Action=Embedded Resource、Copy to Output=Do Not Copy)、清理重建项目均无效,临时手动读取嵌入资源的方案会被WinForms设计器自动生成的代码覆盖。
稳定解决步骤
1. 修正资源管理器的类型引用
打开frmMain.Designer.cs,检查ComponentResourceManager的实例化代码,确保使用的是frmMain的完整类型(而非程序集名称):
- 错误写法:
ComponentResourceManager resources = new ComponentResourceManager(typeof(PixyControl)); - 正确写法:
ComponentResourceManager resources = new ComponentResourceManager(typeof(EA.PixyControl.frmMain));
类型不匹配会导致GetObject尝试加载错误名称的资源文件,这是此类问题的常见诱因。
2. 检查.resx文件的内部引用
用文本编辑器直接打开frmMain.resx,搜索imlProcesses.ImageStream相关条目,确认:
- 资源的
namespace属性为EA.PixyControl type和mimetype指向正确的WinForms类型
示例正确的资源条目:
<data name="imlProcesses.ImageStream" type="System.Windows.Forms.ImageListStreamer, System.Windows.Forms" mimetype="application/x-microsoft.net.object.binary.base64"> <value>...</value> <comment>Namespace: EA.PixyControl</comment> </data>
修正错误后保存文件,重新生成项目。
3. 清理项目缓存
关闭Visual Studio,删除项目目录下的以下文件夹:
binobj.vs(需开启显示隐藏文件)
重新打开项目,执行清理解决方案后再重新生成解决方案,清除可能存在的缓存冲突。
4. 调整发布设置的资源处理
- 打开项目属性 → 发布 → 应用程序文件,确认所有
.resources文件的发布状态为包含(自动),确保嵌入资源被正确打包。 - 若使用ClickOnce发布,进入
项目属性→发布→选项→文件发布选项,取消勾选排除未使用的资源,避免必要资源被误排除。
5. 自定义资源加载逻辑(避免被设计器覆盖)
如果上述方法无效,可通过自定义资源管理器来兼容资源名称差异,同时避免被设计器代码覆盖:
- 创建自定义资源管理器类:
public class CustomResourceManager : ComponentResourceManager { public CustomResourceManager(Type type) : base(type) { } public override object GetObject(string name, CultureInfo culture) { try { return base.GetObject(name, culture); } catch (FileNotFoundException) { // 切换到正确的资源类型加载 var fallbackManager = new ComponentResourceManager(typeof(EA.PixyControl.frmMain)); return fallbackManager.GetObject(name, culture); } } }
- 在
frmMain.cs的构造函数中重新加载资源(跳过设计器生成的代码):
public frmMain() { InitializeComponent(); // 手动重新加载ImageStream资源 var resources = new CustomResourceManager(typeof(EA.PixyControl.frmMain)); imlProcesses.ImageStream = (ImageListStreamer)resources.GetObject("imlProcesses.ImageStream"); }
这种方式不会被WinForms设计器的自动代码覆盖,能稳定解决资源加载问题。
内容的提问来源于stack exchange,提问作者Dave K

