2009-07-31 27 views
19

Estoy creando un método de extensión Distinto donde puedo pasar los criterios como el siguiente.¿Cómo funciona Func <T,TResult>?

persons.Distinct(p => p.Name); 

que tiene el código de la web, pero estoy teniendo dificultades para comprender el propósito de Func<T, TResult>. Además, cuando digo p => p.Name estoy enviando el StringName o estoy enviando el objeto completo Person? Aquí está el nuevo método distinto:

public static class ExtensionMethods 
{ 
    public static IEnumerable<T> Distinct<T>(
     this IEnumerable<T> list, Func<T,object> checker) 
    { 
     return list.Distinct(new GenericComparer<T>(checker)); 
    } 
} 

public class GenericComparer<T> : IEqualityComparer<T> 
{ 
    private Func<T, object> _checker; 

    public GenericComparer(Func<T,object> checker) 
    { 
     _checker = checker; 
    } 

    public bool Equals(T x, T y) 
    { 
     return _checker(x).Equals(_checker(y)); 
    } 

    public int GetHashCode(T obj) 
    { 
     return _checker(obj).GetHashCode(); 
    } 
} 

Y aquí está el uso:

static void Main(string[] args) 
{ 
    var persons = new List<Person>() 
    { 
     new Person() { Id = 1, Name = "Mary"}, 
     new Person() {Id = 2, Name="John"}, 
     new Person() { Id = 3, Name = "Mary"} 
    }; 

    var uniquePersons = persons.Distinct(p => p.Name); 

    foreach(var person in uniquePersons) 
    { 
     Console.WriteLine(person.Name); 
    } 
} 

Respuesta

34

Al hacer esto:

persons.Distinct(p => p.Name); 

Básicamente, se está creando una función sobre la marcha (using lambda expressions), que se ve así:

string theFunction(Person p) 
{ 
    return p.Name; 
} 

Esta es una función que se ajusta a la firma de un delegado Func<Person,String>. El método Distinct puede tomar un delegado (básicamente un puntero de función) que utiliza para determinar si un elemento es distinto o no; en su caso, solo las cadenas únicas (devueltas por la función anterior) se considerarán elementos "distintos". Este delegado se ejecuta en cada elemento de su "personas" enumerable, y los resultados de esas funciones se utilizan. A continuación, crea una secuencia (IEnumerable<Person>) a partir de esos elementos.

+0

+1, pero "En su caso, un elemento es distinto si ningún otro elemento tiene el mismo' Nombre'. Si más de un elemento en la fuente tiene el mismo nombre, solo el primero de ellos estará presente en el resultado. "Además, ninguna sobrecarga del método' Distict() 'toma un selector. ¿Escribiste el tuyo? –

+0

La pregunta OP muestra cómo se define la extensión Distinct ... – ShuggyCoUk

+0

Sí, tengo un método de extensión Distinct de Internet! No lo escribí yo mismo! –

8
Func<T, TResult> 

define una función que acepta un parámetro (de tipo T) y devuelve un objeto (de tipo TResult).

En su caso, si desea una función que toma un objeto Person y devuelve una cadena ... te gustaría

Func<Person, string> 

que es el equivalente a:

string Function(Person p) 
{ 
    return p.Name; 
} 
0

Usted están recuperando las Personas distintas, bajo la suposición de que dos Personas son iguales si tienen el mismo nombre

Si desea un conjunto distinto de nombres, puede usar esto:

IEnumerable<String> names = persons.Select(p => p.Name).Distinct(); 
Cuestiones relacionadas