C# Dictionary使用自定义类为键时如何按属性匹配查询对应值
问题根因
你遇到的问题是C#引用类型的默认相等判断逻辑导致的:class A属于引用类型,默认采用引用相等性做判断,只要两个实例的内存地址不同,就算所有属性值完全一致,相等判断也会返回false。而Dictionary<TKey,TValue>默认使用键类型的默认相等比较器判断键是否相同,所以才会出现ContainsKey(c)返回false的情况。
解决方案
方案1:重写类A的Equals和GetHashCode方法
直接修改类A的实现,自定义相等判断逻辑,按照A1、A2的属性值判断是否相等:
class A { public int A1 { get; set; } public int A2 { get; set; } public override bool Equals(object obj) { return obj is A a && A1 == a.A1 && A2 == a.A2; } public override int GetHashCode() { // .NET Core 2.1+ / .NET 5+ 可直接用HashCode.Combine return HashCode.Combine(A1, A2); // 低版本框架可替换为:return A1.GetHashCode() ^ A2.GetHashCode(); } }
修改后直接调用原有的dict.ContainsKey(c)就会返回true,查询效率保持O(1)。
注意:如果将类A的实例作为Dictionary的键,插入后不要修改A1、A2的属性值,否则实例的哈希值会变化,导致之前插入的键无法被正常检索。
方案2:自定义相等比较器
如果你不能修改类A的源码,可以实现IEqualityComparer<A>接口,在创建Dictionary时传入自定义比较器:
首先实现比较器:
class AEqualityComparer : IEqualityComparer<A> { public bool Equals(A x, A y) { if (x == null && y == null) return true; if (x == null || y == null) return false; return x.A1 == y.A1 && x.A2 == y.A2; } public int GetHashCode(A obj) { return HashCode.Combine(obj.A1, obj.A2); } }
创建Dictionary时指定比较器即可:
Dictionary<A, B> dict = new Dictionary<A, B>(new AEqualityComparer());
后续查询逻辑不需要修改,即可按属性值判断键是否相等。
方案3:使用值元组作为键
如果不需要保留类A实例作为键,可以直接用(int A1, int A2)值元组作为Dictionary的键,值元组默认自带值相等比较逻辑,不需要额外重写方法:
// 定义Dictionary时键类型用值元组 Dictionary<(int A1, int A2), B> dict = new Dictionary<(int A1, int A2), B>(); // 插入时用属性组合作为键 A a = new A { A1 = 1, A2 = 2 }; B b = new B { B1 = 3, B2 = "foo" }; dict.Add((a.A1, a.A2), b); // 查询时直接传属性值即可 var searchKey = (A1:1, A2:2); if(dict.ContainsKey(searchKey)) { Console.WriteLine(dict[searchKey].B2); // 输出foo }
这种方式实现最简单,不需要修改原有类定义,也不需要额外实现比较器。
内容的提问来源于stack exchange,提问作者Luuk
相关产品推荐
相关产品推荐

