VS2019中C# WinForms应用重新实例化主表单未执行初始代码导致驱动器状态变更未被检测的问题咨询
1. 为什么实例化主表单时跳转到_percentComplete字段赋值处?
这是C#的正常执行流程,并非代码错误。当你创建ReadinessStartup类的实例时,代码执行顺序遵循以下规则:
- 首先初始化类的静态字段(如果是第一次创建该类的实例,比如
_allDrives、_monitoredDrives这些标记为static的成员)。 - 然后初始化类的实例字段(包括你看到的
_percentComplete = 0这类带有初始值的实例成员)。 - 最后才会进入类的构造函数,执行
InitializeComponent()和后续代码。
你在ReadinessStartup refresh = new ReadinessStartup();处设置断点,按F11单步执行时,程序会先处理实例字段的初始化逻辑,所以会跳转到_percentComplete的赋值行。这完全符合C#的对象初始化机制,不是bug。
2. 驱动器变更无法检测的问题根源与解决办法
问题根源
你的_allDrives是静态字段,并且只在类第一次加载时调用DriveInfo.GetDrives()初始化一次。静态字段属于类级别的资源,一旦初始化后,后续创建新实例时不会重新执行赋值逻辑。这就导致即使你插入了新驱动器,_allDrives仍然存储的是第一次初始化时的旧驱动器列表,自然无法识别状态变更。
另外,你通过创建新的ReadinessStartup实例来尝试刷新,这种做法不仅会导致多个主窗口实例运行,还因为静态字段的特性,新实例仍然使用旧的驱动器数据,无法解决问题。
解决方案
方案1:每次需要检测时重新获取驱动器列表
不要依赖静态字段存储动态变化的驱动器信息,而是在每次执行扫描/分析操作时,主动调用DriveInfo.GetDrives()获取最新数据。比如在BackgroundWorker的DoWork方法中:
private void bgWorker_DoWork(object sender, DoWorkEventArgs e) { // 每次执行分析前,获取最新的驱动器列表 DriveInfo[] currentDrives = DriveInfo.GetDrives(); // 使用currentDrives进行后续的驱动器状态检查、属性读取操作 foreach (var drive in currentDrives) { // 检查是否是被监控的驱动器,读取空间属性等 } }
方案2:避免创建新实例,刷新现有主窗口
与其创建新的ReadinessStartup实例,不如找到当前已运行的主窗口实例,调用刷新方法重新获取驱动器数据。这样既避免了多实例问题,又能确保使用最新的驱动器信息:
在错误提示表单中,替换创建新实例的代码:
// 查找已打开的ReadinessStartup实例 var existingMainForm = Application.OpenForms.OfType<ReadinessStartup>().FirstOrDefault(); if (existingMainForm != null) { // 调用刷新方法重新执行分析 existingMainForm.RefreshDriveAnalysis(); existingMainForm.Show(); } else { // 如果没有实例,再创建新的 ReadinessStartup newForm = new ReadinessStartup(); newForm.Show(); }
然后在ReadinessStartup类中添加刷新方法:
public void RefreshDriveAnalysis() { // 确保BackgroundWorker未在忙碌时重新执行任务 if (!bgWorker.IsBusy) { bgWorker.RunWorkerAsync(); } }
方案3:调整静态字段的使用(可选)
如果_monitoredDrives的配置可能在运行时变化,同样不要用静态字段存储。可以改为在每次需要时从ConnectionConfig.Connects.GetMonitoring()重新获取,或者在配置更新时主动刷新这个列表。
额外建议
- 如果你使用
System.Timers.Timer定期执行监控任务,确保在定时器的Elapsed事件中也重新获取最新的驱动器列表,而不是复用旧数据。 - 避免在静态字段中存储动态变化的状态,静态字段更适合存储全局不变的配置或资源。
内容的提问来源于stack exchange,提问作者Art Hansen

