Pregunta

Esto es sólo una curiosidad pregunta me preguntaba si alguien tenía una buena respuesta para:

En el .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é utilizar Func<TSource, bool> en lugar de Predicate<TSource>?Parece que el Predicate<TSource> sólo es utilizado por List<T> y Array<T>, mientras que Func<TSource, bool> es utilizado por casi todos los Queryable y Enumerable los métodos y los métodos de extensión...qué pasa con eso?

¿Fue útil?

Solución

Mientras Predicate ha sido introducido al mismo tiempo que List<T> y Array<T>, en .net 2.0, las diferentes Func y Action variantes vienen .net 3.5.

Así que los Func los predicados son utilizados principalmente para la consistencia en los operadores de LINQ.Como de .net 3.5, sobre el uso de Func<T> y Action<T> el guía estados:

Hacer uso de los nuevos tipos de LINQ Func<> y Expression<> lugar de costumbre los delegados y de los predicados

Otros consejos

Me he preguntado esto antes. Me gusta el delegado Predicate<T> - que es agradable y descriptivo. Sin embargo, debe tener en cuenta las sobrecargas de Where:

Where<T>(IEnumerable<T>, Func<T, bool>)
Where<T>(IEnumerable<T>, Func<T, int, bool>)

Esto le permite filtrar en base al índice de la entrada también. Eso es bueno y consistente, Considerando lo siguiente:

Where<T>(IEnumerable<T>, Predicate<T>)
Where<T>(IEnumerable<T>, Func<T, int, bool>)

No sería.

Seguramente la razón real para el uso de Func en lugar de un delegado específico es que C# trata por separado, declaró a los delegados como tipos totalmente diferentes.

Aunque Func<int, bool> y Predicate<int> ambos tienen idéntico argumento y tipos de retorno, que no son de asignación compatible.Así que si cada biblioteca declaró su propio tipo de delegado para cada patrón de delegado, las bibliotecas no sería capaz de interoperar a menos que el usuario inserta un "puente" a los delegados para realizar las 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
    }

Animando a todos a utilizar Func Microsoft tiene la esperanza de que esto va a aliviar el problema de incompatibilidad tipos de delegado.Todos los delegados jugar muy bien juntos, ya que sólo va a ser igualado hasta basado en su parámetro/tipos de retorno.

No resuelve todos los problemas, porque Func (y Action) no puede tener out o ref parámetros, pero esas son las menos utilizadas.

Actualización: en los comentarios Svish dice:

Sin embargo, el cambio de un tipo de parámetro de Func para Predicado y de nuevo, no parece hacer cualquier diferencia?Al menos todavía compila sin ningún tipo de problemas.

Sí, siempre que su programa sólo asigna métodos a los delegados, como en la primera línea de mi Main la función.El compilador silencio genera código para un nuevo objeto delegado que reenvía en el método.Así que en mi Main la función, que podría cambiar x1 para ser de tipo ExceptionHandler2 sin la causa del problema.

Sin embargo, en la segunda línea trato de asignar el primer delegado a otro delegado.Incluso se cree que el 2do tipo de delegado tiene exactamente el mismo parámetro y devolver tipos, el compilador da error CS0029: Cannot implicitly convert type 'ExceptionHandler1' to 'ExceptionHandler2'.

Tal vez esto hará que sea 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 perfectamente buena cosa para asignar a la p y f variables, siempre y cuando lo hago directamente.Pero entonces yo no se puede asignar una de esas variables para el otro.

El consejo (en 3.5 y superior) es el uso de la Action<...> y Func<...> - para el "por qué?" - una de las ventajas es que "Predicate<T>"sólo tiene sentido si usted sabe lo que "predicado" significa - de lo contrario, usted necesita para buscar en el objeto-navegador (etc) para encontrar el signatute.

Por el contrario Func<T,bool> sigue un patrón estándar;De inmediato me puede decir que esta es una función que toma un T y devuelve un bool - no necesitamos entender cualquier terminología - sólo se aplica a mi la verdad la prueba.

Para el "predicado" esto podría haber estado bien, pero aprecio el intento de estandarizar.También permite que una gran cantidad de paridad con los métodos relacionados en el área.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top