231 votes

Pourquoi Func<T,bool> au lieu de prédicat<T>?</T> </T,bool>

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

Dans l' .NET Framework Bibliothèque de Classe, 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 Func<TSource, bool> au lieu de Predicate<TSource>? Semble que le Predicate<TSource> est uniquement utilisée par List<T> et Array<T>, tandis que l' Func<TSource, bool> est utilisé par à peu près tous Queryable et Enumerable méthodes et les méthodes d'extension... qu'est-ce qui?

185voto

Jb Evain Points 11368

Tout Prédicat a été introduit en même temps que la Liste<T> Tableau<T>, dans .net 2.0, les différents Func et l'Action des variantes viennent .net 3.5.

De sorte que ceux Func les prédicats sont utilisés principalement pour des raisons de cohérence dans les opérateurs LINQ. Comme de .net 3.5, sur l'utilisation de la touche Func<> et d'Action<> la directive états:

Ne pas utiliser le nouveau LINQ types "Func<>" et "L'Expression<>" à la place de la coutume les délégués et les prédicats

126voto

Jon Skeet Points 692016

Je me suis demandé cela avant. J’aime la délégué - il fait beau et descriptive. Toutefois, vous devez tenir compte des surcharges de :

Qui permet au filtre basé sur l’index de l’entrée aussi bien. C’est agréable et cohérente, considérant que :

ne serait pas.

36voto

Daniel Earwicker Points 63298

Sûrement la raison pour l'utilisation de Func au lieu d'un délégué spécifique est que C# traite séparément déclaré les délégués totalement différents types.

Même si Func<int, bool> et Predicate<int> les deux ont le même argument et types de retour, ils ne sont pas compatible avec l'assignation. Donc, si chaque bibliothèque a déclaré son propre type de délégué pour chaque modèle de délégué, ces bibliothèques ne serait pas en mesure d'interopérer, à moins que l'utilisateur insère la "transition" délégués d'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 la touche Func, Microsoft espère que cela va résoudre le problème de l'incompatibilité des types délégués. Tous les délégués jouent bien ensemble, parce qu'ils seront appariés sur la base de leurs paramètres/types de retour.

Il ne résout pas tous les problèmes, car Func (et Action) ne peuvent pas avoir l' out ou ref paramètres, mais ceux qui sont moins fréquemment utilisés.

Mise à jour: dans les commentaires Svish dit:

Encore, la commutation d'un type de paramètre de Func pour Prédicat et de retour, ne semblent pas tout la différence? Au moins il encore compile sans aucun problème.

Oui, aussi longtemps que votre programme n'attribue méthodes pour les délégués, comme dans la première ligne de mon Main fonction. Le compilateur silencieusement génère un code à nouveau un délégué de l'objet qui la transmet à la méthode. Donc, dans mon Main de la fonction, je pourrais changer de x1 pour être de type ExceptionHandler2 sans causer un problème.

Cependant, sur la deuxième ligne j'essaie d'attribuer le premier délégué à un autre délégué. Même pensé que 2e délégué type a exactement le même paramètre et types de retour, le compilateur donne erreur CS0029: Cannot implicitly convert type 'ExceptionHandler1' to 'ExceptionHandler2'.

Peut-être cela va 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 IsNegative est une très bonne chose pour l'attribuer à l' p et f variables, aussi longtemps que je le faire directement. Mais alors je ne peux pas attribuer un de ces variables à l'autre.

35voto

Marc Gravell Points 482669

Les conseils (en 3.5 et ci-dessus) consiste à utiliser l' Action<...> et Func<...> - pour le "pourquoi?" - l'avantage est que la "Predicate<T>" n'a de sens que si vous savez ce que "prédicat" signifie - sinon, vous avez besoin de regarder l'objet navigateur (etc) pour trouver la signatute.

À l'inverse Func<T,bool> selon un modèle normalisé; je peux le dire immédiatement que c'est une fonction qui prend un T et renvoie un bool - n'ont pas besoin de comprendre toute la terminologie - il suffit d'appliquer ma vérité test.

Pour "prédicat", ça aurait été OK, mais j'apprécie la tentative de standardiser. Il permet aussi beaucoup de la parité avec les méthodes associées dans ce domaine.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X