Frage

Zur Zeit der HashSet<T> Konstruktor, dass Sie Ihre Gleichheit Vergleich zu definieren, erlaubt sich der HashSet<T>(IEqualityComparer<T> comparer) Konstruktor. Ich möchte diese EqualityComparer als Lambda definieren.

Ich fand dieses Blog-Post , die eine Klasse gemacht hat, dass Sie Ihre comparer durch Lambda generieren kann und dann versteckt die Konstruktion dieser Klasse mit einem Verlängerungsverfahren zum Beispiel einer Ausnahme () zu tun.

Nun möchte Ich mag die gleichen, aber mit einem Konstruktor tun. Ist es möglich, einen Konstruktor durch eine Erweiterung Methode zu schaffen? Oder gibt es eine andere Art, wie ich irgendwie ein HashSet<T>(Func<T,T,int> comparer) schaffen könnte?

- UPDATE -
Aus Gründen der Übersichtlichkeit ist dies (ein Ausschnitt aus) eine freihändig Version von dem, was ich versuche zu erreichen:

HashSet<FileInfo> resultFiles = new HashSet<FileInfo>(
    srcPath.GetFiles(),
    new LambdaComparer<FileInfo>(
        (f1, f2) => f1.Name.SubString(10).Equals(f2.Name.SubString(10))));

oder mehr ideal

HashSet<FileInfo> resultFiles = new HashSet<FileInfo>(
    srcPath.GetFiles(),
    (f1, f2) => f1.Name.SubString(10).Equals(f2.Name.SubString(10)));
War es hilfreich?

Lösung

Nein, Sie können nicht Konstrukteuren hinzufügen (auch mit Erweiterungsmethoden).

Angenommen, Sie einige magische Art und Weise haben von einem Func<T,T,int> zu einem IEqualityComparer<T> zu bekommen (ich interessiert wäre, dass die Blog-Post in zu lesen, wenn Sie es nennen kann) - dann die nächstgelegene Sie tun können, ist wahrscheinlich so etwas wie:

public static class HashSet {
    public static HashSet<T> Create<T>(Func<T, T, int> func) {
        IEqualityComparer<T> comparer = YourMagicFunction(func);
        return new HashSet<T>(comparer);
    }
}

Allerdings; Ich bin zweifelhaft, was man mit einem Lambda für die Gleichstellung tun kann ... Sie haben zwei Konzepte zum Ausdruck bringen: Hashing und wahre Gleichheit. Was wäre Ihr Lambda aussehen? Wenn Sie versuchen, auf das Kind Eigenschaften zu verschieben, dann vielleicht ein Func<T,TValue> die Eigenschaft auszuwählen und EqualityComparer<TValue>.Default intern ... so etwas wie:

class Person {
    public string Name { get; set; }
    static void Main() {
        HashSet<Person> people = HashSetHelper<Person>.Create(p => p.Name);
        people.Add(new Person { Name = "Fred" });
        people.Add(new Person { Name = "Jo" });
        people.Add(new Person { Name = "Fred" });
        Console.WriteLine(people.Count);
    }
}
public static class HashSetHelper<T> {
    class Wrapper<TValue> : IEqualityComparer<T> {
        private readonly Func<T, TValue> func;
        private readonly IEqualityComparer<TValue> comparer;
        public Wrapper(Func<T, TValue> func,
            IEqualityComparer<TValue> comparer) {
            this.func = func;
            this.comparer = comparer ?? EqualityComparer<TValue>.Default;
        }
        public bool Equals(T x, T y) {
            return comparer.Equals(func(x), func(y));
        }

        public int GetHashCode(T obj) {
            return comparer.GetHashCode(func(obj));
        }
    }
    public static HashSet<T> Create<TValue>(Func<T, TValue> func) {
        return new HashSet<T>(new Wrapper<TValue>(func, null));
    }
    public static HashSet<T> Create<TValue>(Func<T, TValue> func,
        IEqualityComparer<TValue> comparer)
    {
        return new HashSet<T>(new Wrapper<TValue>(func, comparer));
    }
}

Andere Tipps

Marc ist richtig. Es gibt keine einfache Möglichkeit für einen einzelnen Lambda die Informationen zum Ausdruck benötigt sowohl für Equals und GetHashCode. Und wenn Sie eine GetHashCode liefern, die unterschiedliche Hashes für „gleich“ Elemente zurückgibt, das wird eine falsche Verhalten führen.

Hier ist mein Kompromiss Umsetzung. Es wird jede generische Func erlauben (wie Marc, ich int außer Acht gelassen, weil Sie es nicht erklären haben), und das wird richtig geben (in, dass es mit dem Vertrag entspricht), aber sehr ineffizient Verhalten.

Ich empfehle Ihnen, mit einem echten IEqualityComparer halten, die Ihren Bedürfnissen entspricht. Es ist eine Schande, C # nicht anonyme innere Klassen nicht unterstützt, aber.

public static class HashSetDelegate
{
    public static HashSet<T> Create<T>(Func<T, T, bool> func)
    {
    return new HashSet<T>(new FuncIEqualityComparerAdapter<T>(func));
    }

    private class FuncIEqualityComparerAdapter<U> : IEqualityComparer<U>
    {
    private Func<U, U, bool> func;
    public FuncIEqualityComparerAdapter(Func<U, U, bool> func)
    {
        this.func = func;
    }

    public bool Equals(U a, U b)
    {
        return func(a, b);
    }

    public int GetHashCode(U obj)
    {
        return 0;
    }  

    }
}

public class HashSetTest
{
    public static void Main()
    {
    HashSet<string> s = HashSetDelegate.Create((string a, string b) => string.Compare(a, b, true) == 0);
    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top