Pregunta

Actualmente el constructor HashSet<T> que le permite definir su comparación de igualdad a sí mismo es el constructor HashSet<T>(IEqualityComparer<T> comparer). Me gustaría definir este EqualityComparer como lambda.

esta entrada del blog que ha hecho de una clase que le permite generar su comparador través de lambda y luego esconde la construcción de esta clase con un método de extensión que ver, por ejemplo, una excepción ().

Ahora me gustaría hacer lo mismo pero con un constructor. ¿Es posible crear un constructor a través de un método de extensión? O hay otra manera que de alguna manera podría crear un HashSet<T>(Func<T,T,int> comparer)?

- ACTUALIZACIÓN -
Para mayor claridad, esto es (un fragmento de) una versión a mano alzada de lo que estoy tratando de lograr:

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

o más idealmente

HashSet<FileInfo> resultFiles = new HashSet<FileInfo>(
    srcPath.GetFiles(),
    (f1, f2) => f1.Name.SubString(10).Equals(f2.Name.SubString(10)));
¿Fue útil?

Solución

No, no puede añadir constructores (incluso con los métodos de extensión).

Asumiendo que tiene alguna forma mágica para obtener de un Func<T,T,int> a un IEqualityComparer<T> (que estaría interesado en leer ese post blog si se puede citar que) - a continuación, lo más cerca que se puede hacer es probablemente algo como:

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

Sin embargo; Estoy dudoso respecto a lo que puede hacer con una lambda por la igualdad ... tiene dos conceptos para expresar: hash, y la verdadera igualdad. ¿Cuáles serían sus lambda parece? Si usted está tratando de aplazar a propiedades secundarias, entonces tal vez un Func<T,TValue> para seleccionar la propiedad, y el uso de EqualityComparer<TValue>.Default internamente ... algo como:

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

Otros consejos

Marc es correcto. No hay manera simple para una sola lambda para expresar la información necesaria para ambos iguales y GetHashCode. Y si usted proporciona un GetHashCode que devuelve diferentes valores hash para los elementos de "iguales", que va a causar un comportamiento incorrecto.

Aquí está mi aplicación compromiso. Se permitirá a cualquier Func genérico (como Marc, que tuvo en cuenta el int porque no explicas), y que dará correcta (en el que se cumple con el contrato), pero el comportamiento muy ineficiente.

recomiendo que empiece con un IEqualityComparer real que se adapte a sus necesidades. Es una pena C # no es compatible con las clases internas anónimas, sin embargo.

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);
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top