c# - funciones - ¿Cómo funciona Func<T, TResult>?
func y action en c# (3)
Estoy creando un método de extensión Distinct donde puedo pasar los criterios como los siguientes.
persons.Distinct(p => p.Name);
Obtuve el código de la web, pero me cuesta mucho entender el propósito de Func<T, TResult>
. Además, cuando digo p => p.Name
estoy enviando el Name
la String
o estoy enviando el objeto Person
completo? Aquí está el nuevo método Distinct:
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);
}
}
Cuando haces esto:
persons.Distinct(p => p.Name);
Básicamente, estás creando una función sobre la marcha ( usando expresiones lambda ), 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 sus "personas" enumerables, y se utilizan los resultados de esas funciones. A continuación, crea una secuencia ( IEnumerable<Person>
) a partir de esos elementos.
Usted está recuperando a las Personas distintas, bajo el supuesto de que dos Personas son iguales si tienen el mismo nombre
Si desea un conjunto distinto de nombres, puede utilizar esto:
IEnumerable<String> names = persons.Select(p => p.Name).Distinct();
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 tome un objeto Person y devuelva una cadena ... desearía
Func<Person, string>
que es el equivalente de:
string Function(Person p)
{
return p.Name;
}