2013-05-19 1 views
4

Je vais avoir un peu de mal à comprendre la raison pour laquelle le code suivant me donne une erreur:lambdas et inférence de type

var funs = Enumerable.Range(0, 10).Select(x => (int y) => x + y); 
foreach (var fun in funs) 
    Console.WriteLine("{0}", fun(10)); 

L'erreur est "Une implicitement déclaration variable locale typée ne peut pas être initialisé avec 'System.Collections.Generic.IEnumerator.Current' ". Je sais comment le résoudre (soit en spécifiant le type de sélectionner, comme Select<int, Func<int, int>> ou en utilisant une méthode d'assistance tels que private static Func<T1, TR> MakeFunc<T1, TR>(Func<T1, TR> f) { return f; } et en utilisant Select(x => MakeFunc(y => x + y)).

Cependant, je voudrais comprendre la raison pour laquelle le compilateur ne peut pas déduire les types.Ma meilleure estimation est, selon 7.15.6, il ne peut pas comprendre si elle devrait traduire le lambda interne à un Func ou Expr.Suis-je correct ou y at-il quelque chose de plus?

Pour référence, voici ce que dit 7.15.6:

"Une fonction anonyme F doit toujours être convertie en un délégué de type D ou une arborescence d'expression de type E, soit directement, soit via l'exécutable. d'une expression de création de délégué nouvelle D (F). Cette conversion détermine le résultat de la fonction anonyme «

+0

Essayez d'envelopper le lambda que vous retournez dans un bloc de code, voyez ce qui se passe? –

+0

Cela compile? –

+1

Cela pourrait aider: http://stackoverflow.com/a/4966409/1223622 –

Répondre

1

La raison est simple:.?!

Comment la compilation peut conclure qu'il devrait être Func<int, int> simple, il ne peut pas

Supposons que vous ayez votre propre délégué: ?

public delegate int F(int i); 

Comment le compilateur choisir entre le Func<int, int> et la F Ce sont des types tout à fait différents, avec deux choses en commun: il y a deux délégués et ont la même signature (un paramètre et un type de retour, tous deux de type int).

Ainsi, le compilateur ne peut pas choisir; vous aurez devez le faire:

var funs = Enumerable.Range(0, 10).Select<int, Func<int,int>>(x => y => x + y); 

ou

var funs = Enumerable.Range(0, 10).Select<int, F>(x => y => x + y); 

Un petit avantage: vous pouvez laisser tomber le int avant la y.