如何在C#中构建仅按引用相等性比较元素的泛型集合?
按引用相等性比较的泛型集合实现方案
要实现你需要的——仅通过对象引用而非值来判断相等性的集合,.NET框架已经提供了开箱即用的解决方案,不用手动实现复杂的相等逻辑。
核心工具:ReferenceEqualityComparer
.NET Core 2.1+ 和 .NET 5+ 中内置了ReferenceEqualityComparer类,它实现了IEqualityComparer<T>接口:
Equals方法直接调用Object.ReferenceEquals,严格按引用判断对象是否相同GetHashCode返回基于对象引用的哈希值,而非值的哈希值,确保引用不同的对象即使值相同也能被正确区分
字符串场景示例
结合HashSet<T>使用这个比较器,就能实现你的需求:引用相同的字符串仅存一份,值相同但引用不同的可以共存。
using System; using System.Collections.Generic; using System.Runtime.CompilerServices; class Program { static void Main() { string s1 = "String1"; string s2 = "String1"; string suffix = "A"; string s3 = "String" + suffix; string s4 = "String" + suffix; // 创建使用引用相等比较器的HashSet var referenceSet = new HashSet<string>(ReferenceEqualityComparer.Instance); referenceSet.Add(s1); referenceSet.Add(s2); // 与s1引用相同,添加失败,集合仅保留一份 referenceSet.Add(s3); referenceSet.Add(s4); // 与s3引用不同,添加成功,集合同时包含s3和s4 Console.WriteLine($"集合元素数量:{referenceSet.Count}"); // 输出:3 foreach (var str in referenceSet) { Console.WriteLine($"元素:{str},引用哈希:{RuntimeHelpers.GetHashCode(str)}"); } } }
扩展到任意泛型引用类型
该方案适用于所有引用类型,比如自定义类的场景:
// 自定义测试类 class Person { public string Name { get; set; } public int Age { get; set; } } class Program { static void Main() { var p1 = new Person { Name = "Alice", Age = 30 }; var p2 = p1; // 与p1引用相同 var p3 = new Person { Name = "Alice", Age = 30 }; // 值相同但引用不同 var personSet = new HashSet<Person>(ReferenceEqualityComparer.Instance); personSet.Add(p1); personSet.Add(p2); // 添加失败 personSet.Add(p3); // 添加成功 Console.WriteLine($"Person集合元素数量:{personSet.Count}"); // 输出:2 } }
封装自定义集合(可选)
如果需要频繁使用这类集合,可以封装一个简化版的自定义集合:
public class ReferenceHashSet<T> : HashSet<T> where T : class { public ReferenceHashSet() : base(ReferenceEqualityComparer.Instance) { } public ReferenceHashSet(IEnumerable<T> collection) : base(collection, ReferenceEqualityComparer.Instance) { } } // 使用时直接实例化 var set = new ReferenceHashSet<string>();
兼容.NET Framework的替代实现
如果需要兼容.NET Framework(该环境无内置ReferenceEqualityComparer),可以手动实现一个简单的引用比较器:
public class ReferenceEqualityComparer<T> : IEqualityComparer<T> where T : class { public static readonly ReferenceEqualityComparer<T> Instance = new(); public bool Equals(T x, T y) => ReferenceEquals(x, y); public int GetHashCode(T obj) => RuntimeHelpers.GetHashCode(obj); }
内容的提问来源于stack exchange,提问作者2474101468
相关产品推荐
相关产品推荐

