Question

Ceci est juste une question de curiosité, je me demandais si quelqu'un avait une bonne réponse à:

Dans le .NET Framework Class Library, nous avons par exemple ces deux méthodes:

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
)

Pourquoi utilisent-ils au lieu de Func<TSource, bool> Predicate<TSource>? On dirait que l'on utilise uniquement List<T> par et Array<T> Queryable, alors que l'on utilise par Enumerable à peu près tous et <=> méthodes et méthodes <=> d'extension ... ce qui se passe avec ça?

Était-ce utile?

La solution

Alors que a été introduit Predicate en même temps que et List<T> Array<T>, en .net 2.0, les différentes variantes Func et Action viennent de .net 3.5.

Alors ces prédicats sont utilisés Func<T> principalement pour la cohérence des opérateurs LINQ. A partir de NET 3.5, sur l'utilisation et Action<T> la Func<> noreferrer ligne directrice précise :

  

N'utiliser les nouveaux types LINQ et Expression<>   Au lieu de la coutume <=>   les délégués et les prédicats

Autres conseils

Je me suis demandé auparavant. J'aime le délégué Predicate<T> - il est agréable et descriptif. Cependant, vous devez considérer les surcharges de Where:

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

Cela vous permet de filtrer en fonction de l'indice de l'entrée ainsi. C'est agréable et cohérente, alors que:

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

ne serait pas.

Certes, la raison réelle pour utiliser au lieu d'un Func délégué spécifique est que C # traite déclarés séparément les délégués que les types totalement différents.

Même si et Func<int, bool> ont tous deux arguments Predicate<int> identiques et types de retour, ils ne sont pas compatibles avec l'affectation. Donc, si chaque bibliothèque a déclaré son propre type de délégué pour chaque motif délégué, ces bibliothèques ne seraient pas en mesure d'interopérer à moins que l'utilisateur insère « de transition » délégués pour effectuer des conversions.

    // 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
    }

En encourageant tout le monde à utiliser Func, Microsoft espère que cela va résoudre le problème des types de délégué incompatibles. Les délégués de chacun jouent bien ensemble, car ils seront simplement jumelés en fonction de leurs paramètres / types de retour.

Il ne résout pas tous les problèmes, parce que Action (et out) ne peuvent pas avoir ou ref paramètres Main, mais ceux-ci sont moins fréquemment utilisés.

Mise à jour: dans les commentaires dit Svish:

  

Cependant, la commutation d'un type de paramètre à partir de   Func à Prédicat et   dos, ne semble pas faire de   différence? il compile encore au moins   sans aucun problème.

Oui, tant que votre programme attribue uniquement des méthodes aux délégués, comme dans la première ligne de ma fonction x1. Le compilateur génère silencieusement code pour un nouvel objet délégué qui transmet à la méthode. Donc, dans ma fonction ExceptionHandler2, je pourrais changer d'être de CS0029: Cannot implicitly convert type 'ExceptionHandler1' to 'ExceptionHandler2' de type sans provoquer IsNegative problème.

Cependant, sur la deuxième ligne je tente d'attribuer le premier délégué à un autre délégué. Même pensé que le type 2 délégué a exactement le même paramètre et les types de retour, le compilateur donne erreur p.

Peut-être cela le rendre plus clair:

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
}

Ma méthode est une parfaite f bonne chose à attribuer au et <=> les variables <=>, aussi longtemps que je le fais directement. Mais je ne peux pas attribuer une de ces variables à l'autre.

Les conseils (à 3,5 et plus) est d'utiliser la et Action<...> Func<...> - « pourquoi » pour la - L'un des avantages est que « Predicate<T> » n'a de sens que si vous savez ce que « principale » désigne -. Sinon vous devez regarder navigateur d'objets (etc) pour trouver le signatute

A l'inverse Func<T,bool> suit un modèle standard; Je peux tout de suite dire que c'est une fonction qui prend une et retourne un T bool - ne pas besoin de comprendre toute la terminologie -. Il suffit d'appliquer mon test de vérité

Pour « prédicat » cela aurait été OK, mais j'apprécie la tentative de normaliser. Il permet aussi beaucoup de parité avec les méthodes connexes dans ce domaine.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top