2016-07-06 96 views
0

如何选择(int.Parse)在这样的Linq表达式中工作?C#Linq和lambda

"1,2,3,4,5".Split(',').Select(int.Parse).ToList();     //ok 
"1,2,3,4,5".Split(',').Select(x => int.Parse(x)).ToList();   //ok 

为什么Console.Writeline的例子返回编译错误?

"1,2,3,4,5".Split(',').Select(Console.WriteLine).ToList();   //error 
"1,2,3,4,5".Split(',').Select(x => Console.WriteLine(x)).ToList(); //ok 

当它被允许省略拉姆达像(X => ....(X))

+9

第4行不应编译为 – fubo

+3

第3个和第4个正试图产生一个List。你认为那个列表可以是*列表*吗? – AakashM

+1

非正式地,'选择'期望它的参数是一个函数,它需要'T's并生成'U's。通常情况下会发生这种情况,例如,如果您传递'int.Parse',编译器会推断出'T = string'和'U = int'。然而,'T'和'U'必须是类型,它们不能是'空白'。 'Console.WriteLine'返回不是有效类型的'void',所以第3行和第4行不会编译(两者)。 – CompuChip

回答

1

选择是一个预测的语句,它把你的对象到您内指定一个新的对象Select。你需要循环和执行的WriteLine:

"1,2,3,4,5".Split(',').ToList().ForEach(x=> { Console.WriteLine(x); }); 

选择需要一个参数Func<char, T>Console.WriteLine不匹配。

0

当方法签名与LinQ期望的相同时,允许使用它。

在你的第一种情况,Select的预期的签名int(或简称Func<string, int>)一个string参数和返回值和int.Parse方法的方法相同签名,这就是为什么它的工作;

而在第二种情况下,Console.WriteLine的签名是与一个string参数和返回值(或特殊类型void的返回值)(或简称Action<string>),因此签名的方法,其Select期望和Console.WriteLine的签名不匹配。

+0

这是'功能'而不是'功能'和顺便说一句:第二个版本不会编译,因为'void'不是'选择'lambda的有效返回类型。 –

3

Select签名看起来有点像这样:

public static IEnumerable<TResult> Select<TSource, TResult>(
      this IEnumerable<TSource> source, 
      Func<TSource, TResult> selector); 

所以对于selector的方法(或lambda)与签名

TResult Method(string s); 

预期。 Console.WriteLine()是退货类型void这是不是有效类型对于TResult。所以实际上两条线

"1,2,3,4,5".Split(',').Select(Console.WriteLine).ToList(); 
"1,2,3,4,5".Split(',').Select(x => Console.WriteLine(x)).ToList(); 

不进行编译。你确定你真的编译了第二行吗?我的编译器为两行提出了错误CS0411

4

Console.WriteLine以及int.Parse都是所谓的方法组。一组方法。由于这些方法的各种重载。它可以是一种方法,也可以是多种方法。

如果编译器可以推断出该组的哪一种方法,方法组可以转换为委托。例如,如果预计有Func<string, int>,方法组int.Parse可以是int.Parse(string)的代表。

这在你的第一个例子中有效。 Select预计Func<T, T2>和您的T已被设置为类型string。但是,它不会而是与您的第二个示例一起使用。因为虽然Console.WriteLine是一个方法组,但该组中的单个方法并不对应于所需的Func<T, T2>,因为该组中的方法的返回类型全部为void

1

几乎所有的LINQ扩展接受返回值的函数Console.WriteLine不返回任何内容,因此它不能用作参数。

"12345".Select(x => { Console.WriteLine(x); return x; }).ToList(); // this will work 

"12345".Select(int.TryParse).ToList(); // this will NOT work because TryParse needs more than one parameter 


"12345".ToList().ForEach(Console.WriteLine); // this will work because .ForEach accepts a method that does not return anything (void) 

"12345".ToList().ForEach(int.Parse); // this will NOT work