Pourquoi Func au lieu de prédicats ?
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?
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.