D'autres ont déjà souligné qu'il existe une infinité de types de délégués possibles que vous auriez pu signifier; ce qui est si spécial Func
qu'il mérite d'être la valeur par défaut au lieu de Predicate
ouAction
ou toute autre possibilité? Et, pour les lambdas, pourquoi est-il évident que l'intention est de choisir la forme de délégué, plutôt que la forme d'arbre d'expression?
Mais nous pourrions dire que Func
c'est spécial, et que le type inféré d'une méthode lambda ou anonyme est Func de quelque chose. Nous aurions encore toutes sortes de problèmes. Quels types aimeriez-vous être déduits pour les cas suivants?
var x1 = (ref int y)=>123;
Il n'y a aucun Func<T>
type qui prend un ref quoi que ce soit.
var x2 = y=>123;
Nous ne connaissons pas le type du paramètre formel, bien que nous connaissions le retour. (Ou le faisons-nous? Le retour est-il int? Long? Court? Octet?)
var x3 = (int y)=>null;
Nous ne connaissons pas le type de retour, mais il ne peut pas être annulé. Le type de retour peut être n'importe quel type de référence ou n'importe quel type de valeur Nullable.
var x4 = (int y)=>{ throw new Exception(); }
Encore une fois, nous ne connaissons pas le type de retour, et cette fois, il peut être nul.
var x5 = (int y)=> q += y;
Est-ce que cela est destiné à être une instruction lambda de retour de vide ou quelque chose qui renvoie la valeur qui a été affectée à q? Les deux sont légaux; que devons-nous choisir?
Maintenant, vous pourriez dire, eh bien, ne supportez aucune de ces fonctionnalités. Soutenez simplement les cas "normaux" où les types peuvent être élaborés. Cela n'aide pas. Comment cela me facilite-t-il la vie? Si la fonctionnalité fonctionne parfois et échoue parfois, je dois encore écrire le code pour détecter toutes ces situations d'échec et donner un message d'erreur significatif pour chacune. Nous devons encore spécifier tout ce comportement, le documenter, écrire des tests pour celui-ci, etc. C'est une fonctionnalité très coûteuse qui permet à l'utilisateur d'économiser peut-être une demi-douzaine de frappes. Nous avons de meilleures façons d'ajouter de la valeur au langage que de passer beaucoup de temps à écrire des cas de test pour une fonctionnalité qui ne fonctionne pas la moitié du temps et qui n'apporte pratiquement aucun avantage dans les cas où cela fonctionne.
La situation où il est réellement utile est:
var xAnon = (int y)=>new { Y = y };
parce qu'il n'y a pas de type "parlable" pour cette chose. Mais nous avons ce problème tout le temps, et nous utilisons simplement l'inférence de type de méthode pour déduire le type:
Func<A, R> WorkItOut<A, R>(Func<A, R> f) { return f; }
...
var xAnon = WorkItOut((int y)=>new { Y = y });
et maintenant l'inférence de type de méthode détermine quel est le type func.
Func<>
accepte jusqu'à 16 arguments.