Jon*_*der 10 .net c# linq lambda
当一个以lambda表达式作为参数的方法(例如Enumerable.Where)被调用而没有在表达式中实际声明变量或方法参数时,它会调用什么?
例如,我熟悉这个lambda表达式语法:
public string GetDigits(string input)
{
return new String(input.Where(i => Char.IsDigit(i)).ToArray());
}
Run Code Online (Sandbox Code Playgroud)
但是,我很惊讶地发现这也可以写成:
public string GetDigits(string input)
{
return new String(input.Where(Char.IsDigit).ToArray());
}
Run Code Online (Sandbox Code Playgroud)
在第二个片段中发生了什么,其中Char.IsDigit()方法(显然)是使用隐式参数调用的?这个语法叫什么?
Ser*_*rvy 17
方法不接受lambdas作为参数.他们接受代表作为参数.lambda只是创建委托的一种方式.
另一种方法是提供方法组,如第二个示例中所做的那样,可以将其转换为委托.
类似的方法是使用匿名方法功能.虽然添加了lambdas,但它或多或少都被lambdas取代了,所以你看不太多.使用该语法的示例将是:
Func<char, bool> predicate = delegate(char c) { return Char.IsDigit(c); };
Run Code Online (Sandbox Code Playgroud)
另一种方法是使用创建委托Delegate.CreateDelegate.(这不是你经常看到的东西.)
最后一种方法是拥有一个从其他地方获得的委托变量.(其他地方会使用其中一个选项创建委托.)
在第二个片段中发生了什么,其中Char.IsDigit()方法(显然)是使用隐式参数调用的?这个语法叫什么?
它没有被调用.这就是重点.我们正在尝试创建一个委托.委托是一个跟踪要调用的方法的对象,以及一个应该调用它的对象.然后,您可以调用委托,它将调用用于创建委托的方法.所以这里你没有调用IsDigit,你正在创建一个指向该IsDigit方法的委托,并且只要调用该委托就会调用它.
当你使用lambda时,你正在创建一个新方法,可能在一个新类中(它们都没有你可以引用的名称,但是它们在运行时会有一个),并且该匿名方法的主体将调用IsDigit.然后lambda解析为指向该匿名方法的委托,该委托维护另一个示例的语义,该方法在调用时调用一个匿名方法,该方法在其实现中调用IsDigit.它正在添加一个额外的间接层(可能会或可能不会在运行时进行优化)来完成同样的事情.
xan*_*tos 10
Enumerable.Where的签名是:
public static IEnumerable<TSource> Where<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate
)
Run Code Online (Sandbox Code Playgroud)
这个:
input.Where(i => Char.IsDigit(i))
Run Code Online (Sandbox Code Playgroud)
相当于写作:
Func<char, bool> temp = i => Char.IsDigit(i);
input.Where(temp);
Run Code Online (Sandbox Code Playgroud)
所以它创建了一个带有i调用参数的匿名函数Char.IsDigit.
这个:
input.Where(Char.IsDigit)
Run Code Online (Sandbox Code Playgroud)
相当于
Func<char, bool> temp = Char.IsDigit;
input.Where(temp);
Run Code Online (Sandbox Code Playgroud)
这相当于:
Func<char, bool> temp = new Func<char, bool>(Char.IsDigit);
input.Where(temp);
Run Code Online (Sandbox Code Playgroud)
所以它创建一个委托Char.IsDigit,然后传递给它input.Where.
所以第二个删除了"中间人"(匿名函数).在这种特殊情况下,它是"合法的",因为i匿名函数的参数"按原样"传递给Char.IsDigit.如果是这样的话会有所不同:
input.Where(i => !Char.IsDigit(i))
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您无法删除中间人(匿名函数).
所有这些都没有名称(或者您可以调用第一个"创建并将委托传递给匿名函数",第二个"创建并传递从方法组创建的委托"......但它们并不漂亮流行语,它们更像是你在做什么)
您Where期望a Func<char, bool>,它是接受char参数并返回a的方法的委托bool.任何匹配此委托的内容都是有效的参数Where.
i是char基于可枚举源的泛型参数-和推断返回类型bool,因为这是拉姆达内的方法调用表达式将返回.Char.IsDigit方法本身也与此匹配.因此,引用该方法是表达同一事物的另一种有效方式.这称为方法组.这两个可能的参数的语义等价Where也是有意义的,如果你考虑对每个lambda表达式,编译器生成一个匿名方法,然后传递该委托所在的匿名方法.
为了说明这一点,请考虑您的原始代码段:
Where(i => Char.IsDigit(i))
Run Code Online (Sandbox Code Playgroud)
以上内容被编译器降低到:
bool AnAnonymousMethod(char i)
{
return Char.IsDigit(i);
}
Run Code Online (Sandbox Code Playgroud)
然后:
Where(AnAnonymousMethod)
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,lambda语法(在没有捕获变量的情况下,如此处)只是编写匿名方法的语法糖,然后在兼容委托的任何地方使用此新编写方法的方法组作为参数是期待.