-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
Background and motivation
I recently had a significant inner-loop performance regression when I added an optional IEqualityComparer<T> to my API. I found out that the reason was that I added the optional comparer argument to the Contains invocation on a ImmutableArray<T>.
Apparently there is no such overload, so it the call was directed from:
public readonly struct ImmutableArray<T>
{
// ...
public bool Contains(T item)
// ...
}And fell back to the much slower Linq extension:
public static class Enumerable
{`
// ...
public static bool Contains<TSource>(this IEnumerable<TSource> source, TSource value, IEqualityComparer<TSource>? comparer);
// ...
}This caused a significant amount of boxing to IEnumerable<T> each time Contains was called. Most methods in the API at the moment contain overloads that accept an optional IEqualityComparer<T>?, so it was quite surprising that this API did not.
API Proposal
namespace System.Linq;
public static partial class ImmutableArrayExtensions
{
public static bool Contains<T>(this ImmutableArray<T> immutableArray, T item, IEqualityComparer<T>? comparer)
{
var self = immutableArray;
return self.IndexOf(item, 0, self.Length, equalityComparer) >= 0;
}
}API Usage
ImmutableArray<string> items = ImmutableArray.Create("abc", "DEF");
Assert.True(items.Contains("Abc", StringComparer.InvariantCultureIgnoreCase));
Assert.True(items.Contains("Def", StringComparer.InvariantCultureIgnoreCase));Alternative Designs
No response
Risks
This has a really low risk of breaking something. It should increase the overall performance when Contains is used where the programmer was not aware of this issue.