J'ai le code suivant:
Func<string, bool> comparer = delegate(string value) {
return value != "0";
};
Cependant, ce qui suit ne compile pas:
var comparer = delegate(string value) {
return value != "0";
};
Pourquoi le compilateur ne peut-il pas comprendre qu'il s'agit d'un Func<string, bool>
? Il prend un paramètre de chaîne et renvoie un booléen. Au lieu de cela, cela me donne l'erreur:
Impossible d'attribuer une méthode anonyme à une variable locale typée implicitement.
J'ai une supposition et c'est que si la version var compilait , elle manquerait de cohérence si j'avais ce qui suit:
var comparer = delegate(string arg1, string arg2, string arg3, string arg4, string arg5) {
return false;
};
Ce qui précède n'aurait pas de sens puisque Func <> n'autorise que jusqu'à 4 arguments (dans .NET 3.5, ce que j'utilise). Peut-être que quelqu'un pourrait clarifier le problème. Merci.
Func<>
accepte jusqu'à 16 arguments.Func<string, bool>
? CelaConverter<string, bool>
me ressemble !Dim comparer = Function(value$) value <> "0"
Réponses:
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 dePredicate
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?Il n'y a aucun
Func<T>
type qui prend un ref quoi que ce soit.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?)
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.
Encore une fois, nous ne connaissons pas le type de retour, et cette fois, il peut être nul.
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:
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:
et maintenant l'inférence de type de méthode détermine quel est le type func.
la source
Seul Eric Lippert le sait, mais je pense que c'est parce que la signature du type de délégué ne détermine pas de manière unique le type.
Considérez votre exemple:
Voici deux inférences possibles pour ce que
var
devrait être:Lequel doit déduire le compilateur? Il n'y a aucune bonne raison de choisir l'un ou l'autre. Et bien que a
Predicate<T>
soit fonctionnellement équivalent à aFunc<T, bool>
, ils sont toujours de types différents au niveau du système de type .NET. Le compilateur ne peut donc pas résoudre sans ambiguïté le type de délégué et doit échouer l'inférence de type.la source
Eric Lippert a un vieux post à ce sujet où il dit
la source
Différents délégués sont considérés comme des types différents. par exemple,
Action
est différent deMethodInvoker
, et une instance deAction
ne peut pas être affectée à une variable de typeMethodInvoker
.Donc, étant donné un délégué anonyme (ou lambda) comme
() => {}
, est-ce unAction
ou unMethodInvoker
? Le compilateur ne peut pas le dire.De même, si je déclare un type de délégué prenant un
string
argument et renvoyant unbool
, comment le compilateur saurait-il que vous vouliez vraiment unFunc<string, bool>
au lieu de mon type de délégué? Il ne peut pas déduire le type de délégué.la source
Les points suivants proviennent du MSDN concernant les variables locales implicitement typées:
Référence MSDN: variables locales typées implicitement
Considérant ce qui suit concernant les méthodes anonymes:
Référence MSDN: méthodes anonymes
Je soupçonne que puisque la méthode anonyme peut en fait avoir des signatures de méthode différentes, le compilateur est incapable de déduire correctement quel serait le type le plus approprié à attribuer.
la source
Mon message ne répond pas à la question réelle, mais il répond à la question sous-jacente de:
"Comment puis-je éviter d'avoir à taper des caractères fugaces comme
Func<string, string, int, CustomInputType, bool, ReturnType>
?" [1]Étant le programmeur paresseux / hacky que je suis, j'ai expérimenté l'utilisation
Func<dynamic, object>
- qui prend un seul paramètre d'entrée et renvoie un objet.Pour plusieurs arguments, vous pouvez l'utiliser comme ceci:
Conseil: vous pouvez utiliser
Action<dynamic>
si vous n'avez pas besoin de renvoyer un objet.Oui, je sais que cela va probablement à l'encontre de vos principes de programmation, mais cela a du sens pour moi et probablement pour certains codeurs Python.
Je suis plutôt novice chez les délégués ... je voulais juste partager ce que j'ai appris.
[1] Cela suppose que vous
Func
n'appelez pas une méthode qui nécessite un paramètre prédéfini , auquel cas vous devrez taper cette fugly string: /la source
Et ça?
la source