以下陈述完全可以。
var sb = new string[] { "line1", "line2" };
sb.ForEach(Console.WriteLine);
// same as sb.ForEach(item => Console.WriteLine(item));
这种不使用 lambda 表达式中的参数的做法叫什么名字?
谢谢,
“方法组转换”是您正在寻找的术语。它自动将一组方法(重载)转换为委托。
在这种情况下,Console.WriteLine
是一组大约 19 个不同的方法,它们都以相同的名称重载。然后编译器确定这些重载之一是否与预期的委托兼容(Action<String>
是唯一的委托)。由于有一个匹配,它会为您转换Console.WriteLine
为new Action<String>(Console.WriteLine)
。
将形式的 lambda 转换Method(x => f(x))
为Method(f)
称为eta reduction。我不知道 C# 编译器是否在内部执行 eta 缩减,但它确实支持将方法组(在您的情况下为 Console.WriteLine)转换为委托类型(可能Action<string>
在这里)。
C# 编译器会将重载包装Console.WriteLine(string)
在Action<string>
委托中并将其传递给您的ForEach
方法。
C# 规范定义了将方法组转换为兼容委托类型的规则:
6.6 方法组转换
从方法组(第 7.1 节)到兼容委托类型存在隐式转换(第 6.1 节)。给定一个委托类型 D 和一个被归类为方法组的表达式 E,如果 E 包含至少一个适用于其正常形式(第 7.5.3.1 节)构造的参数列表的方法,则存在从 E 到 D 的隐式转换通过使用 D 的参数类型和修饰符
虽然前面的两个答案都很好 - 并且正确 - 如果您有如下代码,还有一个额外的答案:
int i = 7;
return () => Foo(i);
这就是所谓的闭包,因为虽然 lambda 没有参数,但它将整数包含在父作用域中。当使用返回的匿名方法时,它仍然可以使用变量 i,就好像它从未超出范围一样......而且因为它是封闭的,所以它没有!
根据您的原始问题,您展示了 eta 减少或方法组转换。你的问题措辞听起来有点像结束语。