2010-01-02 6 views
16

Plusieurs questions C# sur StackOverflow vous demandent comment créer des délégués/lambdas anonymes avec les paramètres out ou ref. Voir, par exemple:Pourquoi les délégués anonymes/lambdas ne déduisent-ils pas les types de paramètres out/ref?

Pour ce faire, il vous suffit de spécifier le type de paramètre, comme dans:

public void delegate D(out T p); 
// ... 
D a = (out T t) => { ... };  // Lambda syntax. 
D b = delegate(out T t) { ... }; // Anonymous delegate syntax. 

Qu'est-ce que Je suis curieux de savoir pourquoi le type est explicitement requis. Y a-t-il une raison particulière que c'est le cas? Autrement dit, du point de vue du compilateur/du langage, pourquoi les éléments suivants ne sont-ils pas autorisés?

D a = (out t) => { ... };  // Lambda syntax -- implicit typing. 
D b = delegate(out t) { ... }; // Anonymous delegate syntax -- implicit typing. 

ou mieux encore, il suffit:

D a = (t) => { ... };  // Lambda syntax -- implicit typing and ref|out-ness. 
D b = delegate(t) { ... }; // Anonymous delegate syntax -- implicit typing and ref|out-ness. 
+3

Je suis curieux à ce sujet moi-même. Espérons qu'Eric Lippert remarquera ce post ... il est le plus susceptible de donner une réponse significative à cela. – LBushkin

+2

LBushkin, si vous voulez apporter quelque chose à mon attention, vous pouvez toujours me l'envoyer via le lien de contact sur mon blog. –

+0

Pour les méthodes anonymes avec le mot-clé 'delegate', la règle est que vous ne spécifiez rien (omettez même la parenthèse'() ') ou spécifiez la signature complète incluant les types de paramètres et les modificateurs comme' ref'/'out'. Donc 'ref' /' out' ne fait pas exception. Pour les lambdas, ton idée a du sens, mais je ne suis pas sûre si je pense que c'est une bonne idée. La syntaxe '(out t) => {...}' donne l'impression que "out" est le type du paramètre. Alors 't => {...}' est meilleur, mais il pourrait être "dangereux" si quelqu'un oublie la signification de 'D' et édite le corps' {...} 'du lambda sans réaliser le' out' nature de 't'. –

Répondre

17

question intéressante.

D'abord, considérons la différence entre les méthodes anonymes et les lambdas. Du point de vue du rédacteur du compilateur, la différence la plus importante est que lambdas peut exiger que le compilateur infère le type des paramètres de la cible à laquelle le lambda est assigné; Les méthodes anonymes C# 2 n'ont pas cette fonctionnalité. Cette fonctionnalité semble être une petite différence mais en fait, elle a des ramifications majeures sur l'implémentation du compilateur. Voir ma série de blog sur ce sujet pour quelques réflexions sur les raisons qui est:

http://blogs.msdn.com/ericlippert/archive/2007/01/10/lambda-expressions-vs-anonymous-methods-part-one.aspx

nous donc maintenant de venir à votre question réelle: pourquoi ne pas déduire extériorité/refness du type de cible aux paramètres du lambda. Autrement dit, si nous avons un délégué D (out int x) alors sûrement D d = x => {x = 10; } pourrait déduire que x est "out int".

Il n'y a pas de raison technique pour laquelle je ne sais pas pourquoi nous ne pourrions pas faire cela. En interne dans le compilateur, les types out/ref sont représentés comme des types comme les autres.

Cependant, les fonctionnalités ne sont pas réalisées uniquement parce qu'elles peuvent être réalisées; ils se font parce qu'il y a une raison impérieuse de le faire.Pour les lambdas, la raison impérieuse de faire une inférence de type en premier lieu est LINQ; nous voulons être en mesure de faire une transformation syntaxique simple sur une compréhension de requête dans un appel de méthode avec lambdas, et laisser le moteur d'inférence de type de méthode élaborer les types de tous les paramètres lambda. Aucune des méthodes LINQ générées n'a de délégué avec des paramètres out ou ref.

Donc, nous n'avons aucune raison impérieuse de faire la fonctionnalité. Les délégués qui ont des paramètres out/ref sont relativement rares. Et l'attribution de lambdas à ces délégués est encore plus rare. Donc, c'est une fonctionnalité dont nous n'avons pas besoin, et qui ne profite presque à personne.

C# 3 était le «pôle long» de l'horaire Visual Studio; nous avons eu le plus grand nombre de jours de travail prévus pour toute équipe qui expédie un composant dans VS. Cela signifiait que tous les jours nous avons glissé l'horaire, l'ensemble division glissé. Cela a fortement découragé de consacrer du temps à des fonctions inutiles qui n'ont profité à personne. Donc le travail n'a jamais été fait. Je suis d'accord que ce serait bien d'être plus cohérent ici, mais il est peu probable que cela se produise. Nous avons beaucoup de priorités plus élevées.

+1

Je pense que tout le monde est parfaitement conscient de l'engouement des gars, mais il est vraiment bon de savoir que la porte n'est pas fermée pour une raison technique et qu'il est théoriquement possible de le faire un jour. Merci pour la contribution, Eric! –

2

De Eric Lippert's comment pourquoi la déclaration et l'affectation d'une variable var ne peuvent pas être séparés:

Je suis d'accord que, en principe, cela pourrait se faire , mais c'est plus compliqué en pratique que ne le laisserait supposer votre rapide esquisse. var exige non seulement qu'il y ait un initialiseur, mais aussi que l'initialiseur ne fasse pas référence à la variable. Si vous avez int M (out int), vous pouvez dire "int x = M (out x);" mais vous ne pouvez pas dire "var x = M (out x);" parce que pour faire une résolution de surcharge sur M, nous devons connaître le type de x, ce que nous essayons de comprendre. Serait-il légal de dire "var s, si (b) M (out s), sinon s = 0;" ?

Je suppose que la réponse à votre question est similaire, compte tenu, par exemple,

D a = (out var x) => x = M(out x); 
+2

Je ne suis pas si sûr. Comment expliquez-vous le fait que si vous supprimez le mot-clé 'out', le compilateur peut faire l'inférence? Le type de délégué 'D' devrait complètement déterminer le type de' x'. – LBushkin

+1

Je ne suis pas convaincu que c'est le cas. Ici, nous savons que nous essayons de nous retrouver avec quelque chose qui ressemble à un «D». Si le résultat à droite ne correspond pas, cela ne sera-t-il pas évident? Avec l'exemple 'var', cela pourrait être n'importe quoi, donc le compilateur n'a aucun indice sur ce à quoi devrait ressembler la" bonne réponse ". [Oups! LBushkin m'a battu au punch!] –

Questions connexes