C#中访问字典值触发KeyNotFoundException的问题求助
解决注册表键读取的KeyNotFoundException问题
问题重现
编写C#代码遍历注册表路径数组,将对应项的Start值存入Dictionary<string, uint>,但使用错误的键格式访问时抛出KeyNotFoundException:
原注册表遍历代码
string[] keys = { @"SYSTEM\CurrentControlSet\Services\XblGameSave", @"SYSTEM\CurrentControlSet\Services\XboxNetApiSvc", @"SYSTEM\CurrentControlSet\Services\XboxGipSvc", @"SYSTEM\CurrentControlSet\Services\XblAuthManager", @"SYSTEM\CurrentControlSet\Services\wisvc", @"SYSTEM\CurrentControlSet\Services\Spooler", @"SYSTEM\CurrentControlSet\Services\PrintNotify", @"SYSTEM\CurrentControlSet\Services\MapsBroker", @"SYSTEM\CurrentControlSeSet\Services\bthserv", // 路径拼写错误 @"SYSTEM\CurrentControlSet\Services\DiagTrack", @"SYSTEM\CurrentControlSet\Services\dmwappushservice", @"SYSTEM\CurrentControlSet\Services\diagsvc", @"SYSTEM\CurrentControlSet\Services\diagnosticshub.standardcollector.service", @"SYSTEM\CurrentControlSet\Services\WdiServiceHost", @"SYSTEM\CurrentControlSet\Services\WdiSystemHost", @"SYSTEM\CurrentControlSet\Services\AJRouter", @"SYSTEM\CurrentControlSet\Services\ALG", @"SYSTEM\CurrentControlSet\Services\CertPropSvc", @"SYSTEM\CurrentControlSet\Services\Fax", @"SYSTEM\CurrentControlSet\Services\CscService", @"SYSTEM\CurrentControlSet\Services\RetailDemo", @"SYSTEM\CurrentControlSet\Services\seclogon", @"SYSTEM\CurrentControlSet\Services\SCardSvr", @"SYSTEM\CurrentControlSet\Services\ScDeviceEnum", @"SYSTEM\CurrentControlSet\Services\SCPolicySvc", @"SYSTEM\CurrentControlSet\Services\SysMain", @"SYSTEM\CurrentControlSet\Services\WerSvc", @"SYSTEM\CurrentControlSet\Services\DoSvc", @"SYSTEM\CurrentControlSet\Services\lfsvc", @"SYSTEM\CurrentControlSet\Services\SEMgrSvc", @"SYSTEM\CurrentControlSet\Services\PhoneSvc", @"SYSTEM\CurrentControlSet\Services\RemoteRegistry", @"SYSTEM\CurrentControlSet\Services\WdiServiceHost", // 重复键 @"SYSTEM\CurrentControlSet\Services\WdiSystemHost", // 重复键 @"SYSTEM\CurrentControlSet\Services\feafes", @"SYSTEM\CurrentControlSet\Services\ALG", // 重复键 @"SYSTEM\CurrentControlSet\Services\CertPropSvc", // 重复键 @"SYSTEM\CurrentControlSet\Services\Fax", // 重复键 @"SYSTEM\CurrentControlSet\Services\CscService", // 重复键 @"SYSTEM\CurrentControlSet\Services\WalletService", @"SYSTEM\CurrentControlSet\Services\WSearch", @"SYSTEM\CurrentControlSet\Services\W32Time", @"SYSTEM\CurrentControlSet\Services\tzautoupdate", @"SYSTEM\CurrentControlSet\Services\CDPSvc", @"SYSTEM\CurrentControlSet\Services\DusmSvc", @"SYSTEM\CurrentControlSet\Services\fhsvc", @"SYSTEM\CurrentControlSet\Services\PcaSvc", }; Dictionary<string, uint> dict = new Dictionary<string, uint>(); foreach (string key in keys) { RegistryKey rkey = Registry.LocalMachine.OpenSubKey(key, true); try { dict.Add(key, Convert.ToUInt32(rkey.GetValue("Start", RegistryValueKind.DWord))); } catch (Exception) { // 空catch块,隐藏错误 } finally { rkey?.Dispose(); } }
错误的访问代码
uint value = dict["@\"SYSTEM\\\\CurrentControlSet\\\\Services\\\\XblGameSave\""];
错误原因
- 键格式不匹配:访问字典时使用了带额外引号和冗余转义的字符串,而字典中的键是原始的
@"SYSTEM\CurrentControlSet\Services\XblGameSave"(实际存储值为SYSTEM\CurrentControlSet\Services\XblGameSave),两者完全不同,导致找不到对应键。 - 原代码的潜在问题:
- 注册表路径拼写错误:
CurrentControlSeSet应为CurrentControlSet,导致该路径无法打开,不会被加入字典。 - 重复键:数组中存在多个重复路径,
dict.Add会抛出异常但被空catch块吞噬,导致这些键无法存入字典。 GetValue参数错误:第二个参数应为默认值,而非RegistryValueKind.DWord,会引发类型转换错误。- 空catch块:隐藏所有异常,无法定位哪些键读取失败。
- 注册表路径拼写错误:
解决步骤
1. 修正键的访问方式
直接使用与数组中完全一致的字符串访问字典,无需额外转义或引号:
// 正确的访问方式(与数组中字符串一致) uint value = dict[@"SYSTEM\CurrentControlSet\Services\XblGameSave"]; // 或者不用@符号,手动转义反斜杠 uint value = dict["SYSTEM\\CurrentControlSet\\Services\\XblGameSave"];
2. 修复原代码的潜在问题
以下是修正后的完整代码:
using Microsoft.Win32; using System; using System.Collections.Generic; string[] keys = { @"SYSTEM\CurrentControlSet\Services\XblGameSave", @"SYSTEM\CurrentControlSet\Services\XboxNetApiSvc", @"SYSTEM\CurrentControlSet\Services\XboxGipSvc", @"SYSTEM\CurrentControlSet\Services\XblAuthManager", @"SYSTEM\CurrentControlSet\Services\wisvc", @"SYSTEM\CurrentControlSet\Services\Spooler", @"SYSTEM\CurrentControlSet\Services\PrintNotify", @"SYSTEM\CurrentControlSet\Services\MapsBroker", @"SYSTEM\CurrentControlSet\Services\bthserv", // 修正拼写错误 @"SYSTEM\CurrentControlSet\Services\DiagTrack", @"SYSTEM\CurrentControlSet\Services\dmwappushservice", @"SYSTEM\CurrentControlSet\Services\diagsvc", @"SYSTEM\CurrentControlSet\Services\diagnosticshub.standardcollector.service", @"SYSTEM\CurrentControlSet\Services\WdiServiceHost", @"SYSTEM\CurrentControlSet\Services\WdiSystemHost", @"SYSTEM\CurrentControlSet\Services\AJRouter", @"SYSTEM\CurrentControlSet\Services\ALG", @"SYSTEM\CurrentControlSet\Services\CertPropSvc", @"SYSTEM\CurrentControlSet\Services\Fax", @"SYSTEM\CurrentControlSet\Services\CscService", @"SYSTEM\CurrentControlSet\Services\RetailDemo", @"SYSTEM\CurrentControlSet\Services\seclogon", @"SYSTEM\CurrentControlSet\Services\SCardSvr", @"SYSTEM\CurrentControlSet\Services\ScDeviceEnum", @"SYSTEM\CurrentControlSet\Services\SCPolicySvc", @"SYSTEM\CurrentControlSet\Services\SysMain", @"SYSTEM\CurrentControlSet\Services\WerSvc", @"SYSTEM\CurrentControlSet\Services\DoSvc", @"SYSTEM\CurrentControlSet\Services\lfsvc", @"SYSTEM\CurrentControlSet\Services\SEMgrSvc", @"SYSTEM\CurrentControlSet\Services\PhoneSvc", @"SYSTEM\CurrentControlSet\Services\RemoteRegistry", @"SYSTEM\CurrentControlSet\Services\feafes", @"SYSTEM\CurrentControlSet\Services\WalletService", @"SYSTEM\CurrentControlSet\Services\WSearch", @"SYSTEM\CurrentControlSet\Services\W32Time", @"SYSTEM\CurrentControlSet\Services\tzautoupdate", @"SYSTEM\CurrentControlSet\Services\CDPSvc", @"SYSTEM\CurrentControlSet\Services\DusmSvc", @"SYSTEM\CurrentControlSet\Services\fhsvc", @"SYSTEM\CurrentControlSet\Services\PcaSvc", }; Dictionary<string, uint> dict = new Dictionary<string, uint>(); foreach (string key in keys) { // 跳过已存在的键,避免重复添加异常 if (dict.ContainsKey(key)) continue; // 使用using自动释放RegistryKey资源,无需手动Dispose using RegistryKey rkey = Registry.LocalMachine.OpenSubKey(key); if (rkey == null) { Console.WriteLine($"无法打开注册表项: {key}"); continue; } try { object startValue = rkey.GetValue("Start"); if (startValue == null) { Console.WriteLine($"注册表项 {key} 中不存在Start值"); continue; } // 先判断值类型是否为DWord,再转换 if (rkey.GetValueKind("Start") == RegistryValueKind.DWord) { dict.Add(key, Convert.ToUInt32(startValue)); } else { Console.WriteLine($"注册表项 {key} 的Start值不是DWord类型"); } } catch (Exception ex) { Console.WriteLine($"读取注册表项 {key} 时出错: {ex.Message}"); } } // 按数组顺序安全访问字典值 foreach (string key in keys) { if (dict.TryGetValue(key, out uint value)) { Console.WriteLine($"{key}: {value}"); } else { Console.WriteLine($"{key}: 未找到值"); } }
关键修正点
- 修正了注册表路径的拼写错误。
- 添加重复键检查,避免
Add方法抛出异常。 - 使用
using语句自动释放RegistryKey资源,简化代码。 - 优化
GetValue逻辑,先判断值是否存在及类型是否正确。 - 替换空catch块为错误日志,便于排查问题。
- 使用
TryGetValue安全访问字典,避免抛出KeyNotFoundException。
额外说明
若需要严格保持数组的顺序访问,建议使用OrderedDictionary替代Dictionary——虽然.NET Core 3.0+及.NET 5+的Dictionary已保证插入顺序,但OrderedDictionary的顺序语义更明确。
内容的提问来源于stack exchange,提问作者KrakenZ
相关产品推荐
相关产品推荐

