Esta es solo una pregunta de curiosidad que me preguntaba si alguien tenía una buena respuesta para:
En .NET Framework Class Library tenemos, por ejemplo, estos dos métodos:
public static IQueryable<TSource> Where<TSource>(
this IQueryable<TSource> source,
Expression<Func<TSource, bool>> predicate
)
public static IEnumerable<TSource> Where<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate
)
¿Por qué usan en Func<TSource, bool>
lugar de Predicate<TSource>
? Parece que la Predicate<TSource>
única es utilizado por List<T>
y Array<T>
, mientras Func<TSource, bool>
es utilizado por casi todo Queryable
y Enumerable
métodos y métodos de extensión ... ¿qué pasa con eso?
Respuestas:
Si bien
Predicate
se ha introducido al mismo tiempo queList<T>
yArray<T>
, en .net 2.0, las diferentesFunc
yAction
variantes provienen de .net 3.5.Por lo tanto, esos
Func
predicados se usan principalmente para mantener la coherencia en los operadores LINQ. A partir de .net 3.5, sobre el usoFunc<T>
yAction<T>
los estados de la guía :fuente
Me he preguntado esto antes. Me gusta el
Predicate<T>
delegado, es agradable y descriptivo. Sin embargo, debe tener en cuenta las sobrecargas deWhere
:Eso también le permite filtrar según el índice de la entrada. Eso es agradable y consistente, mientras que:
no lo sería
fuente
Where
método de extensión espredicate
. Heh = P.Seguramente la razón real para usar en
Func
lugar de un delegado específico es que C # trata a los delegados declarados por separado como tipos totalmente diferentes.A pesar de que
Func<int, bool>
yPredicate<int>
ambos tienen idénticos tipos de argumentos y de retorno, no son una asignación compatible. Entonces, si cada biblioteca declara su propio tipo de delegado para cada patrón de delegado, esas bibliotecas no podrán interactuar a menos que el usuario inserte delegados "puente" para realizar conversiones.Al alentar a todos a usar Func, Microsoft espera que esto aliviará el problema de los tipos de delegados incompatibles. Los delegados de todos jugarán muy bien juntos, porque solo se emparejarán según sus parámetros / tipos de retorno.
No resuelve todos los problemas, porque
Func
(yAction
) no puede tenerout
oref
parámetros, pero esos son menos utilizados.Actualización: en los comentarios Svish dice:
Sí, siempre que su programa solo asigne métodos a los delegados, como en la primera línea de mi
Main
función. El compilador genera silenciosamente código para crear un nuevo objeto delegado que reenvía el método. Entonces, en miMain
función, podría cambiarx1
para ser de tipoExceptionHandler2
sin causar un problema.Sin embargo, en la segunda línea trato de asignar el primer delegado a otro delegado. Incluso si el segundo tipo de delegado tiene exactamente el mismo parámetro y tipos de retorno, el compilador da error
CS0029: Cannot implicitly convert type 'ExceptionHandler1' to 'ExceptionHandler2'
.Quizás esto lo aclare:
Mi método
IsNegative
es perfectamente bueno para asignar a las variablesp
yf
, siempre que lo haga directamente. Pero entonces no puedo asignar una de esas variables a la otra.fuente
Func<T, bool>
o enPredicate<T>
lugar de tener el tipo inferido por el compilador.El consejo (en 3.5 y superior) es usar
Action<...>
yFunc<...>
- para el "¿por qué?" - una ventaja es que "Predicate<T>
" solo tiene sentido si sabe lo que significa "predicado"; de lo contrario, debe buscar en el buscador de objetos (etc.) para encontrar el firmante.Por el contrario,
Func<T,bool>
sigue un patrón estándar; Puedo decir de inmediato que esta es una función que tomaT
y devuelve unbool
- no es necesario que entienda ninguna terminología - solo aplique mi prueba de verdad.Para "predicado" esto podría haber estado bien, pero agradezco el intento de estandarizar. También permite mucha paridad con los métodos relacionados en esa área.
fuente