La raison réelle de l'utilisation Func
au lieu d'un délégué spécifique est certainement que C # traite les délégués déclarés séparément comme des types totalement différents.
Même si Func<int, bool>
et les Predicate<int>
deux ont arguments identiques et types de retour, ils ne sont pas compatibles avec l' affectation. Ainsi, si chaque bibliothèque déclarait son propre type de délégué pour chaque modèle de délégué, ces bibliothèques ne seraient pas en mesure d'interopérer à moins que l'utilisateur n'insère des délégués de "pontage" 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 résoudra le problème des types de délégués incompatibles. Les délégués de chacun joueront bien ensemble, car ils seront juste mis en correspondance en fonction de leurs paramètres / types de retour.
Il ne résout pas tous les problèmes, parce que Func
(et Action
) ne peuvent pas avoir out
ou ref
paramètres, mais ceux -ci sont moins fréquemment utilisés.
Mise à jour: dans les commentaires Svish dit:
Pourtant, le passage d'un type de paramètre de Func à Predicate et inversement ne semble pas faire de différence? Au moins, il compile toujours sans aucun problème.
Oui, tant que votre programme affecte uniquement des méthodes aux délégués, comme dans la première ligne de ma Main
fonction. Le compilateur génère silencieusement du code pour créer un nouvel objet délégué qui le transmet à la méthode. Donc, dans ma Main
fonction, je pouvais changer x1
de type ExceptionHandler2
sans causer de problème.
Cependant, sur la deuxième ligne, j'essaie d'affecter le premier délégué à un autre délégué. Même si le deuxième type de délégué a exactement les mêmes paramètres et types de retour, le compilateur donne une erreurCS0029: Cannot implicitly convert type 'ExceptionHandler1' to 'ExceptionHandler2'
.
Peut-être que cela le rendra 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 à attribuer aux variables p
et f
, tant que je le fais directement. Mais alors je ne peux pas assigner une de ces variables à l'autre.