Domanda

Al momento il costruttore HashSet<T> che permette di definire la confronto di uguaglianza se stessi è il costruttore HashSet<T>(IEqualityComparer<T> comparer). Vorrei definire questo EqualityComparer come lambda.

questo post del blog che ha fatto una classe che permette di generare il vostro operatore di confronto attraverso lambda e poi nasconde la costruzione di questa classe con un metodo estensione per fare ad esempio una eccezione ().

Ora vorrei fare lo stesso, ma con un costruttore. E 'possibile creare un costruttore attraverso un metodo di estensione? O c'è un altro modo ho potuto in qualche modo creare un HashSet<T>(Func<T,T,int> comparer)?

- UPDATE -
Per chiarezza, questo è (un frammento di) una versione a mano libera di quello che sto cercando di realizzare:

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

o più idealmente

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

Soluzione

No, non è possibile aggiungere costruttori (anche con metodi di estensione).

Supponendo di avere qualche modo magico di ottenere da un Func<T,T,int> a un IEqualityComparer<T> (Sarei interessato nel leggere quel post del blog, se si può citarlo) - poi il più vicino si può fare è probabilmente qualcosa come:

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);
    }
}

Tuttavia; Sono dubbioso su cosa si può fare con un lambda per l'uguaglianza ... avete due concetti per esprimere: hash e vera uguaglianza. Quale sarebbe la vostra lambda simile? Se si sta tentando di rinviare alle proprietà bambino, allora forse un Func<T,TValue> per selezionare la proprietà, e utilizzare EqualityComparer<TValue>.Default internamente ... qualcosa come:

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));
    }
}

Altri suggerimenti

Marc è giusto. Non c'è modo semplice per un singolo lambda per esprimere le informazioni necessarie per entrambe le Equals e GetHashCode. E se si fornisce un GetHashCode che restituisce diversi hash per elementi "uguali", che causerà un comportamento corretto.

Ecco la mia implementazione compromessi. Esso permetterà a qualsiasi Funz generico (come Marc, ho ignorato l'int perché non si spieghi), e che darà corretto (in quanto conforme al contratto), ma un comportamento molto inefficiente.

Vi consiglio di bastone con un vero e proprio IEqualityComparer che soddisfi le vostre esigenze. E 'un peccato C # non supporta le classi interne anonime, però.

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);
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top