method - not exists list c#
¿Por qué Func<T, bool> en lugar de Predicate<T>? (4)
Esta es solo una pregunta curiosa. Me preguntaba si alguien tenía una buena respuesta para:
En la biblioteca de clases de .NET Framework 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 Func<TSource, bool>
lugar de Predicate<TSource>
? Parece que Predicate<TSource>
solo se usa en List<T>
y Array<T>
, mientras que Func<TSource, bool>
se usa en casi todos los métodos y métodos de extensión Queryable
y Enumerable
... ¿qué pasa con eso?
El consejo (en 3.5 y superior) es usar la Action<...>
y la Func<...>
- para el "¿por qué?" - una ventaja es que " Predicate<T>
" solo tiene sentido si sabes lo que significa "predicado"; de lo contrario, debes buscar en el buscador de objetos (etc.) para encontrar la firma.
A la inversa, Func<T,bool>
sigue un patrón estándar; Inmediatamente puedo decir que esta es una función que toma una T
y devuelve un bool
(no es necesario que comprenda ninguna terminología), solo aplique mi prueba de la verdad.
Para el "predicado" esto podría haber estado bien, pero aprecio el intento de estandarizar. También permite mucha paridad con los métodos relacionados en esa área.
Me he preguntado esto antes. Me gusta el delegado Predicate<T>
- es agradable y descriptivo. Sin embargo, debe considerar las sobrecargas de Where
:
Where<T>(IEnumerable<T>, Func<T, bool>)
Where<T>(IEnumerable<T>, Func<T, int, bool>)
Eso le permite filtrar basándose en el índice de la entrada también. Eso es agradable y consistente, mientras que:
Where<T>(IEnumerable<T>, Predicate<T>)
Where<T>(IEnumerable<T>, Func<T, int, bool>)
no seria
Seguramente la razón real para usar Func
lugar de un delegado específico es que C # trata a los delegados declarados por separado como tipos totalmente diferentes.
Aunque Func<int, bool>
y Predicate<int>
tienen tipos de argumento y retorno idénticos, no son compatibles con la asignación. Entonces, si cada biblioteca declarara su propio tipo de delegado para cada patrón de delegado, esas bibliotecas no podrían interoperar a menos que el usuario inserte delegados de "puente" para realizar conversiones.
// declare two delegate types, completely identical but different names:
public delegate void ExceptionHandler1(Exception x);
public delegate void ExceptionHandler2(Exception x);
// a method that is compatible with either of them:
public static void MyExceptionHandler(Exception x)
{
Console.WriteLine(x.Message);
}
static void Main(string[] args)
{
// can assign any method having the right pattern
ExceptionHandler1 x1 = MyExceptionHandler;
// and yet cannot assign a delegate with identical declaration!
ExceptionHandler2 x2 = x1; // error at compile time
}
Al alentar a todos a usar Func, Microsoft espera que esto alivie el problema de los tipos de delegados incompatibles. Los delegados de todos jugarán muy bien juntos, ya que solo se compararán en función de sus parámetros / tipos de retorno.
No resuelve todos los problemas, ya que Func
(y Action
) no pueden tener parámetros out
o ref
, pero se usan con menos frecuencia.
Actualización: en los comentarios Svish dice:
Sin embargo, cambiar un tipo de parámetro de Func a Predicate y viceversa, ¿no parece hacer ninguna diferencia? Al menos todavía compila sin ningún problema.
Sí, siempre que su programa solo asigne métodos a los delegados, como en la primera línea de mi función Main
. El compilador genera silenciosamente código para un nuevo objeto delegado que reenvía al método. Así que en mi función Main
, podría cambiar x1
para que sea del tipo ExceptionHandler2
sin causar un problema.
Sin embargo, en la segunda línea, trato de asignar el primer delegado a otro delegado. Aun cuando el segundo tipo de delegado tiene exactamente los mismos parámetros y tipos de retorno, el compilador CS0029: Cannot implicitly convert type ''ExceptionHandler1'' to ''ExceptionHandler2''
error CS0029: Cannot implicitly convert type ''ExceptionHandler1'' to ''ExceptionHandler2''
.
Tal vez esto lo hará más claro:
public static bool IsNegative(int x)
{
return x < 0;
}
static void Main(string[] args)
{
Predicate<int> p = IsNegative;
Func<int, bool> f = IsNegative;
p = f; // Not allowed
}
Mi método IsNegative
es una cosa perfectamente buena para asignar a las variables p
y f
, siempre y cuando lo haga directamente. Pero entonces no puedo asignar una de esas variables a la otra.
Si bien Predicate
se introdujo al mismo tiempo que List<T>
y Array<T>
, en .net 2.0, las diferentes variantes de Func
y Action
provienen de .net 3.5.
Por lo tanto, esos predicados funcionales se utilizan principalmente para mantener la coherencia en los operadores LINQ. A partir de .net 3.5, sobre el uso de Func<T>
y Action<T>
la guía establece :
Utilice los nuevos tipos de LINQ
Func<>
yExpression<>
lugar de delegados y predicados personalizados