-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Closed as not planned
Closed as not planned
Copy link
Labels
api-needs-workAPI needs work before it is approved, it is NOT ready for implementationAPI needs work before it is approved, it is NOT ready for implementationarea-System.Collections
Milestone
Description
Background and motivation
This proposal attempts to consolidate a number of issues requesting IEqualityComparer<T> and IComparer<T> combinators acting on common collection types, e.g. #33873, #44796, #77183 (comment) and #19644. Defining structural equality/order comparison on collection types is a common requirement, for example when working with incremental source generators.
API Proposal
namespace System.Collections.Generic;
public static class EqualityComparer
{
// Equality comparison using sequence equality
public static IEqualityComparer<IEnumerable<T>> CreateEnumerableComparer<T>(IEqualityComparer<T> elementComparer = null);
public static IEqualityComparer<ReadOnlyMemory<T>> CreateMemoryComparer<T>(IEqualityComparer<T> elementComparer = null);
public static IEqualityComparer<IReadOnlyList<T>> CreateListComparer<T>(IEqualityComparer<T> elementComparer = null);
// Equality comparison à la HashSetEqualityComparer
// cf. https://github.com/dotnet/runtime/blob/5ef4c68b08b5f55df91ce62cca86babfdb321162/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSetEqualityComparer.cs
public static IEqualityComparer<IReadOnlySet<T>> CreateSetComparer<T>(IEqualityComparer<T> elementComparer = null);
public static IEqualityComparer<IReadOnlyDictionary<TKey, TValue>> CreateDictionaryComparer<TKey, TValue>(IEqualityComparer<TKey> keyComparer= null, IEqualityComparer<TValue> valueComparer = null);
}
public static class Comparer
{
// Comparison using lexicographic ordering
public static IComparer<IEnumerable<T>> CreateEnumerableComparer<T>(IComparer<T> elementComparer = null);
public static IComparer<ReadOnlyMemory<T>> CreateMemoryComparer<T>(IComparer<T> elementComparer = null);
public static IComparer<IReadOnlyList<T>> CreateListComparer<T>(IComparer<T> elementComparer = null);
}API Usage
IEqualityComparer<string[]> stringArrayComparer = EqualityComparer.CreateEnumerableComparer(StringComparer.InvariantCultureIgnoreCase);
var dictionary = new Dictionary<string[], object>(stringArrayComparer);
dictionary.Add(new string[] { "key" }, null);
dictionary.ContainsKey(new string[] { "KEY" }); // trueIComparer<string[]> stringArrayComparer = Comparer.CreateEnumerableComparer(StringComparer.InvariantCultureIgnoreCase);
var dictionary = new SortedDictionary<string[], object>(stringArrayComparer);
dictionary.Add(new string[] { "key" }, null);
dictionary.ContainsKey(new string[] { "KEY" }); // trueAlternative Designs
Making the combinators generic on the collection type would allow construction-time specialization and help with devirtualization, e.g.
public static IEqualityComparer<TEnumerable> CreateEnumerableComparer<TEnumerable, TElement>(IEqualityComparer<TElement> elementComparer = null)
where TEnumerable : IEnumerable<TElement>
{
elementComparer ??= EqualityComparer<T>.Default;
if (typeof(IReadOnlyList<TElement>).IsAssignableFrom(typeof(TEnumerable)))
{
return new ListSequenceComparer<TEnumerable, TElement>(elementComparer));
}
return new EnumerableSequenceComparer<TEnumerable, TElement>(elementComparer);
}But obviously that would make calling the combinators more complicated:
IEqualityComparer<int[]> arrayComparer = EqualityComparer.CreateEnumerableComparer<int[], int>();Full alternative proposal:
namespace System.Collections.Generic;
public static class EqualityComparer
{
// Equality comparison using sequence equality
public static IEqualityComparer<TEnumerable> CreateEnumerableComparer<TEnumerable, T>(IEqualityComparer<T> elementComparer = null)
where TEnumerable : IEnumerable<T> { }
public static IEqualityComparer<ReadOnlyMemory<T>> CreateMemoryComparer<T>(IEqualityComparer<T> elementComparer = null) { }
// Equality comparison à la HashSetEqualityComparer
// cf. https://github.com/dotnet/runtime/blob/5ef4c68b08b5f55df91ce62cca86babfdb321162/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSetEqualityComparer.cs
public static IEqualityComparer<TSet> CreateSetComparer<TSet, T>(IEqualityComparer<T> elementComparer = null)
where TSet : IReadOnly<T> { }
public static IEqualityComparer<TDictionary> CreateDictionaryComparer<TDictionary, TKey, TValue>(IEqualityComparer<TKey> keyComparer= null, IEqualityComparer<TValue> valueComparer = null)
where TDictionary : IDictionary<TKey, TValue> { }
}
public static class Comparer
{
// Comparison using lexicographic ordering
public static IComparer<TEnumerable> CreateEnumerableComparer<TEnumerable, T>(IComparer<T> elementComparer = null)
where TEnumerable : IEnumerable<T> { }
public static IComparer<ReadOnlyMemory<T>> CreateMemoryComparer<T>(IComparer<T> elementComparer = null) { }
}Risks
No response
theodorzoulias, Uladzimir-Lashkevich, jnm2, antoniofreire, kronic and 3 moreSergio0694, jnm2, antoniofreire and Zodt
Metadata
Metadata
Assignees
Labels
api-needs-workAPI needs work before it is approved, it is NOT ready for implementationAPI needs work before it is approved, it is NOT ready for implementationarea-System.Collections