在C#中能否对Dictionary实现一次查询完成存在性检查与取值?
解决方案
针对Dictionary中KeyValuePair是值类型无法直接和null比较的问题,有几种方式可以实现单次查询同时完成存在性检查与取值:
1. 使用可空结构体(C# 8.0+)
利用C#的可空值类型特性,把目标变量声明为可空键值对类型,直接判断是否为null即可(底层会自动处理值类型的默认值与null的映射):
Dictionary<(int X, int Y), ITileData<(int X, int Y)>> srchField = new(); KeyValuePair<(int X, int Y), ITileData<(int X, int Y)>>? next; while ((next = srchField.FirstOrDefault(x => !x.Value.Reached)) != null) { // 使用next.Value获取找到的键值对 var targetItem = next.Value; // ... }
2. 自定义扩展方法规避默认值误判
如果字典中可能存在键/值为默认值的元素,担心FirstOrDefault返回的默认实例被误判为有效元素,可以写一个扩展方法直接返回可空结果:
public static class EnumerableExtensions { public static KeyValuePair<TKey, TValue>? FirstOrDefaultNullable<TKey, TValue>( this IEnumerable<KeyValuePair<TKey, TValue>> source, Func<KeyValuePair<TKey, TValue>, bool> predicate) { foreach (var item in source) { if (predicate(item)) return item; } return null; } }
使用方式和你熟悉的引用类型模式完全一致,且只会遍历集合一次:
KeyValuePair<(int X, int Y), ITileData<(int X, int Y)>>? next; while ((next = srchField.FirstOrDefaultNullable(x => !x.Value.Reached)) != null) { var targetItem = next.Value; // ... }
3. 用Take(1)简化逻辑(无需扩展方法)
如果不想额外写扩展方法,也可以用Take(1)获取第一个匹配元素,通过foreach处理结果(序列最多包含一个元素):
while (true) { var match = srchField.Where(x => !x.Value.Reached).Take(1); bool hasMatch = false; foreach (var next in match) { hasMatch = true; // 使用next处理找到的元素 // ... } if (!hasMatch) break; }
这种方式同样只遍历一次集合,找到第一个匹配元素后立即停止。
内容的提问来源于stack exchange,提问作者Jez
相关产品推荐
相关产品推荐

