Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IEnumerable<Func<T,S>> and LINQ type inference

C# compiler can correctly infer type of s (string) in these snippets:

 Func<int, string, string> f1 = (n, s) => s.Substring(n);
 Func<int, Func<string, string>> f2 = n => s => s.Substring(n);

But it can't in this one [1]:

 var numbers = Enumerable.Range(1, 10);
 IEnumerable<Func<string, string>> fs = numbers.Select(n => s => s.Substring(n));

To make it work one has to do something like this:

var fs = numbers.Select(n => new Func<string, string>(s => s.Substring(n));

or

var fs = numbers.Select(f2);

And the question is - why type inference doesn't work in [1] if all needed information about types is known beforehand?

like image 699
rkrahl Avatar asked Dec 23 '14 12:12

rkrahl


1 Answers

All the information about the type isn't known beforehand. In your first working snippet, you're telling it on both lines which delegate type you want s => s.Substring(n) to be converted to.

In your second snippet, the only place where that information is present is in the assignment of the result of Select... and that isn't used as part of overload and type inference when the compiler is working out what the Select call itself means.

So the options are:

  • Do it in two steps, using f2
  • Cast the lambda expression in the Select call, or use a new operator as per your snippet
  • Provide the type arguments for Select directly:

    var fs = numbers.Select<int, Func<string, string>>(n => s => s.Substring(n));
    
like image 149
Jon Skeet Avatar answered Nov 03 '22 05:11

Jon Skeet