.NET是否有支持自定义元素比较的集合逐元素Compare方法?
解决方案
针对你需要的跨.NET版本(4.8/4.8.1、6.0、8.0)的集合逐元素比较需求,以下是符合要求的内置方法/实现方式:
.NET 6.0+(含.NET 8.0)
直接使用Span<T>.CompareTo(Span<T>, IComparer<T>)方法,配合CollectionsMarshal.AsSpan将IReadOnlyCollection<string>转换为Span<string>,完美支持自定义元素比较器,返回-1/0/1的标准比较结果:
using System.Collections.Generic; using System.Runtime.InteropServices; // 调用示例 IReadOnlyCollection<string> coll1 = new[] { "apple", "banana" }; IReadOnlyCollection<string> coll2 = new[] { "Apple", "Banana" }; int comparisonResult = CollectionsMarshal.AsSpan(coll1) .CompareTo(CollectionsMarshal.AsSpan(coll2), StringComparer.OrdinalIgnoreCase);
该方法会按顺序逐元素比较,首个不同元素的比较结果即为整体结果;若一个集合是另一个的前缀,较短的集合视为更小。
.NET Framework 4.8/4.8.1
.NET Framework中没有直接提供带自定义元素比较器的集合逐元素比较内置方法,但可以通过Comparer<IEnumerable<string>>.Create创建可复用的比较器,内部逻辑依赖内置的元素比较器,无需自行编写通用遍历逻辑:
using System.Collections.Generic; // 预定义可复用的集合比较器 private static readonly Comparer<IEnumerable<string>> _ordinalStringCollectionComparer = Comparer<IEnumerable<string>>.Create((a, b) => { using var enumA = a.GetEnumerator(); using var enumB = b.GetEnumerator(); while (true) { bool hasNextA = enumA.MoveNext(); bool hasNextB = enumB.MoveNext(); if (!hasNextA && !hasNextB) return 0; if (!hasNextA) return -1; if (!hasNextB) return 1; int elemCompare = StringComparer.Ordinal.Compare(enumA.Current, enumB.Current); if (elemCompare != 0) return elemCompare; } }); // 调用示例 int comparisonResult = _ordinalStringCollectionComparer.Compare(coll1, coll2);
自定义类的IComparable实现
结合上述方案,自定义类的CompareTo方法可以这样写,实现跨版本兼容:
using System; using System.Collections.Generic; #if NET6_0_OR_GREATER using System.Runtime.InteropServices; #endif public class MyCustomClass : IComparable<MyCustomClass> { public IReadOnlyCollection<string> MyCollection { get; } public MyCustomClass(IReadOnlyCollection<string> collection) { MyCollection = collection; } public int CompareTo(MyCustomClass other) { if (other == null) return 1; #if NET6_0_OR_GREATER return CollectionsMarshal.AsSpan(MyCollection) .CompareTo(CollectionsMarshal.AsSpan(other.MyCollection), StringComparer.Ordinal); #else return _ordinalStringCollectionComparer.Compare(MyCollection, other.MyCollection); #endif } #if !NET6_0_OR_GREATER private static readonly Comparer<IEnumerable<string>> _ordinalStringCollectionComparer = Comparer<IEnumerable<string>>.Create((a, b) => { using var enumA = a.GetEnumerator(); using var enumB = b.GetEnumerator(); while (true) { bool hasNextA = enumA.MoveNext(); bool hasNextB = enumB.MoveNext(); if (!hasNextA && !hasNextB) return 0; if (!hasNextA) return -1; if (!hasNextB) return 1; int elemCompare = StringComparer.Ordinal.Compare(enumA.Current, enumB.Current); if (elemCompare != 0) return elemCompare; } }); #endif }
内容的提问来源于stack exchange,提问作者Kjara
相关产品推荐
相关产品推荐

