2011-10-12 1 views
11

ConsidéronsMéthode d'inférence ne fonctionne pas avec le groupe de procédé

void Main() 
{ 
    var list = new[] {"1", "2", "3"}; 
    list.Sum(GetValue); //error CS0121 
    list.Sum(s => GetValue(s)); //works ! 
} 

double GetValue(string s) 
{ 
    double val; 
    double.TryParse(s, out val); 
    return val; 
} 

La description de l'erreur CS0121 est

L'appel est ambiguë entre les méthodes ou les propriétés suivantes: 'System.Linq.Enumerable.Sum<string>(System.Collections.Generic.IEnumerable<string>, System.Func<string,decimal>)' et 'System.Linq.Enumerable.Sum<string>(System.Collections.Generic.IEnumerable<string>, System.Func<string,decimal?>) »

Ce que je ne comprends pas, c'est quoi dans formation ne s => GetValue(s) donner au compilateur que simplement GetValue ne - n'est pas le dernier sucre syntaxique pour le premier?

Répondre

18

La réponse de Mark est correcte mais pourrait utiliser un peu plus d'explications.

Le problème est en effet dû à une subtile différence entre la façon dont les groupes de méthodes sont traités et la manière dont les lambdas sont traités.

Plus précisément, la différence subtile est que un groupe de méthode est considérée comme convertible à un type délégué uniquement sur la base de savoir si les arguments match pas non plus sur la base de savoir si le type de retour matchs. Lambdas vérifie les arguments et le type de retour.

La raison de cette règle impaire est que les conversions de groupe de méthodes aux délégués sont essentiellement une solution du problème de résolution de surcharge. Supposons que D soit le type de délégué double D(string s) et M est un groupe de méthodes contenant une méthode qui prend une chaîne et renvoie une chaîne. Lorsque vous résolvez la signification d'une conversion de M vers D, nous surchargons la résolution comme si vous aviez dit M (chaîne). Résolution de surcharge choisirait le M qui prend une chaîne et renvoie une chaîne, et donc M est convertible en ce type de délégué même si la conversion entraînera une erreur plus tard. Tout comme la résolution "normale" de surcharge réussirait si vous disiez "string s = M (null);" - la résolution de surcharge réussit, même si cela provoque un échec de conversion plus tard.

Cette règle est subtile et un peu bizarre. Le résultat de ceci ici est que votre groupe de méthode est convertible en tous les différents types de délégués qui sont les seconds arguments de chaque version de Sum qui prend un délégué. Comme aucune meilleure conversion ne peut être trouvée, la résolution de surcharge du groupe de méthodes Sum est ambiguë.

Les règles de conversion de groupe de méthodes sont plausibles mais un peu impair en C#. Je suis un peu vexé qu'ils ne sont pas compatibles avec les conversions lambda plus «intuitivement correctes».

+0

Si vous aviez un horodateur, comment les changeriez-vous? Souhaitez-vous leur faire réfléchir sur les types de retour, comme les lambdas?Ou feriez-vous un changement subtil différent? – configurator

+0

Intéressant! Je jouais avec LinqPad et en effet, même si j'ai 'double D1 (chaîne s)' et 'int D1 (chaîne s)', un groupe de méthodes avec une signature de 'chaîne M (chaîne)' produirait une ambiguïté erreur d'appel - même si les deux signatures ne correspondent pas de toute façon. Ceci par opposition à un lambda, qui les essaierait tous et vous donnerait une erreur de conversion sur le dernier (le premier?) Qu'il essaye. –

+0

Cependant, s'il n'y a pas de problème de surcharge (et que la mauvaise signature est utilisée), l'erreur du groupe de méthodes ("M a le mauvais type de retour") est légèrement plus informative que celle de lambda ("Impossible de convertir 'double'") –

8

s => GetValue(s) est une expression lambda et GetValue est un groupe de méthodes, ce qui est une chose complètement différente. Ils peuvent tous deux être considérés comme du sucre syntaxique pour new Func<string,double>(...) mais la seule façon dont ils sont liés l'un à l'autre est que l'expression lambda inclut un appel à GetValue(). En ce qui concerne la conversion en délégué, les groupes de méthodes ont des règles de conversion différentes de celles des expressions lambda par rapport aux types de retour. Voir Why is Func<T> ambiguous with Func<IEnumerable<T>>? et Overloaded method-group argument confuses overload resolution?.

+0

Intéressant (upvoted) - va vérifier les liens –

Questions connexes