4

I'm having a bit of trouble understanding the reason behind why the following code is giving me an error:

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

The error is "An implicitly typed local variable declaration cannot be initialized with 'System.Collections.Generic.IEnumerator.Current'". I know how to fix it (either by specifying the type to select, such as Select<int, Func<int, int>> or by using a helper method such as private static Func<T1, TR> MakeFunc<T1, TR>(Func<T1, TR> f) { return f; } and using Select(x => MakeFunc(y => x + y)).

However, I'd like to understand the reason the compiler can't deduce the types. My best guess so far is, according to 7.15.6, it can't figure out if it should translate the inner lambda to a Func or Expr. Am I correct or is there something more to it?

For reference, here's what 7.15.6 says:

"An anonymous function F must always be converted to a delegate type D or an expression tree type E, either directly or through the execution of a delegate creation expression new D(F). This conversion determines the result of the anonymous function."

usr
  • 168,620
  • 35
  • 240
  • 369
Vlad Ciobanu
  • 1,473
  • 1
  • 11
  • 11

1 Answers1

2

The reason is simple:

HOW can the compile conclude that it should be Func<int, int>? He simple cannot!

Suppose you had your own delegate:

 public delegate int F(int i);

How could the compiler choose between the Func<int, int> and the F? These are totally different types, with two things in common: there are both delegates and have the same signature (one parameter and return type, both of type int).

So the compiler cannot choose; you will have have to do it:

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

or

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

One little advantage: you can drop the int before the y.

Martin Mulder
  • 12,642
  • 3
  • 25
  • 54