Skip to content

API proposal: Comparison by key #33877

@jnm2

Description

@jnm2

Before

You have to write out the selector twice:

names.Sort((first, second) => string.Compare(
    first.Identifier.GetIdentifierText(),
    second.Identifier.GetIdentifierText(),
    StringComparer.OrdinalIgnoreCase));

(Comparer.Sequence is #33873)

statements.OrderBy(GetNameSegments, Comparer.Sequence(
    Comparer.Create((first, second) => string.Compare(
        first.Identifier.GetIdentifierText(),
        second.Identifier.GetIdentifierText(),
        StringComparer.OrdinalIgnoreCase)))

After

// Proposal 1
names.Sort(Comparer.By(
    (SimpleNameSyntax name) => name.Identifier.GetIdentifierText(),
    StringComparer.OrdinalIgnoreCase));

// Proposal 2
names.Sort(Comparer<SimpleNameSyntax>.By(
    name => name.Identifier.GetIdentifierText(),
    StringComparer.OrdinalIgnoreCase))
// Proposal 1
statements.OrderBy(GetNameSegments, Comparer.Sequence(Comparer.By(
    (SimpleNameSyntax name) => name.Identifier.GetIdentifierText(),
    StringComparer.OrdinalIgnoreCase));

// Proposal 2
statements.OrderBy(GetNameSegments, Comparer.Sequence(Comparer<SimpleNameSyntax>.By(
    name => name.Identifier.GetIdentifierText(),
    StringComparer.OrdinalIgnoreCase))

Proposal 1

namespace System.Collections
{
    public sealed class Comparer : IComparer, ISerializable
    {
+       public static IComparer<T> By<T, TKey>(
+           Func<T, TKey> keySelector,
+           IComparer<TKey>? keyComparer = null);

        // No other static members are declared by Comparer
    }
}

Proposal 2

namespace System.Collections.Generic
{
    public abstract partial class Comparer<T> : IComparer, IComparer<T>
    {
+       public static IComparer<T> By<TKey>(
+           Func<T, TKey> keySelector,
+           IComparer<TKey>? keyComparer = null);

        // Other static members declared by Comparer:
        public static Comparer<T> Create(Comparison<T> comparison);
    }
}

Draft implementation

Click to expand
private sealed class KeyComparer<T, TKey> : IComparer<T>
{
    private readonly Func<T, TKey> keySelector;
    private readonly IComparer<TKey> keyComparer;

    public KeyComparer(Func<T, TKey> keySelector, IComparer<TKey> keyComparer)
    {
        this.keySelector = keySelector;
        this.keyComparer = keyComparer;
    }

    public int Compare([AllowNull] T x, [AllowNull] T y)
    {
        return keyComparer.Compare(
            keySelector.Invoke(x!),
            keySelector.Invoke(y!));
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions