How Do Select(int.解析)在这样的 Linq 表达式中工作?
"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
当允许省略 lambda 时,例如 (x => ....(十))
Console.WriteLine
以及int.Parse
都是所谓的方法组。方法组。因为这些方法的各种重载。它可以是一种方法,也可以是多种方法。
如果编译器可以推断出组的哪个方法是指方法组,则可以将方法组转换为委托。例如,方法组int.Parse
可以是int.Parse(string)
是否需要Func<string, int>
的委托。
这在您的第一个示例中有效。 Select
需要Func<T, T2>
,并且您的T
已设置为类型 string
。但是,它不适用于您的第二个示例。因为虽然Console.WriteLine
是一个方法组,但该组中没有一个方法对应于所需的Func<T, T2>
因为组中所有方法的返回类型都是void
。
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。
Select 是一个投影语句,它将您的对象转换为您在Select
中指定的新对象。你需要循环并执行 WriteLine:
"1,2,3,4,5".Split(',').ToList().ForEach(x=> { Console.WriteLine(x); });
选择需要参数Func<char, T>
,Console.WriteLine
不匹配。
几乎所有的 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
当方法签名与 LinQ 预期相同时,允许这样做。
在第一种情况下,Select
的预期签名是一个具有一个string
参数和返回值int
(或简称Func<string, int>
)的方法,并且int.Parse
方法具有相同的签名,这就是它工作的原因;
而在第二种情况下,Console.WriteLine
的签名是一个string
参数的方法,没有返回值(或特殊类型void
的返回值)(或简称Action<string>
),因此Select
期望的签名和Console.WriteLine
的签名不匹配。