了解lambda参数语法

本文关键字:语法 参数 lambda 了解 | 更新日期: 2023-09-27 17:58:41

 static uint Fibonacci(uint n)
    {
        return n <= 1 ? n : Fibonacci(n - 1) + Fibonacci(n - 2);
    }
Func<uint> fibN = () => Fibonacci(n);
Func<int, int, int> add = (a, b) => a + b;

我理解add函数语法:它返回一个+b语句的int结果,int a和b参数"进入"该语句。

但是为什么fibN函数有空的参数块((?n不是作为参数"转到"这个函数吗?请帮我理解一下这一刻。

了解lambda参数语法

您的第一个lambda:

Func<uint> fibN = () => Fibonacci(n);

没有任何参数。现在它不会编译,因为变量n是必需的。此变量可以来自lambda参数,也可以来自当前作用域。由于lambda没有参数,也不存在当前作用域中的变量n,因此它将不会编译。

要使其编译,您可以执行以下操作:

uint n = 1; // Or any other value
Func<uint> fibN = () => Fibonacci(n);

注:使用类似于第一个lambda的lambas语句,您将依赖于当前范围来执行它们。因此,编译的匿名方法不是静态的。另一方面,您的第二个lambda语句不依赖于当前作用域(因为它使用的所有变量都是lambda参数(,并且这个lambda被编译成一个静态匿名方法。这可能有助于您了解lambda语句是如何编译的。基本上,lambda语句被编译成普通的匿名方法。

考虑以下代码:

class Program
{
    static void Main(string[] args)
    {
        Func<uint> fibN = () => Fibonacci(n);
    }
    static uint Fibonacci(uint n)
    {
        return n <= 1 ? n : Fibonacci(n - 1) + Fibonacci(n - 2);
    }
}

只要没有合适类型的变量n可供使用,它就不会令人尴尬。但是,如果添加:

uint n = 5;

转换为Main方法或

static uint n = 5;

到类,代码将编译。


让我们拆开。对于以下代码:

static void Main(string[] args)
{
    uint n = 3;
    Func<uint> fibN = () => Fibonacci(n);
}

我们得到:

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  .maxstack  3
  .locals init ([0] class [mscorlib]System.Func`1<uint32> fibN,
           [1] class Utils.Program/'<>c__DisplayClass1' 'CS$<>8__locals2')
  IL_0000:  newobj     instance void Utils.Program/'<>c__DisplayClass1'::.ctor()
  IL_0005:  stloc.1
  IL_0006:  nop
  IL_0007:  ldloc.1
  IL_0008:  ldc.i4.3
  IL_0009:  stfld      uint32 Utils.Program/'<>c__DisplayClass1'::n
  IL_000e:  ldloc.1
  IL_000f:  ldftn      instance uint32         Utils.Program/'<>c__DisplayClass1'::'<Main>b__0'()
  IL_0015:  newobj     instance void class [mscorlib]System.Func`1<uint32>::.ctor(object,
                                                                              native int)
  IL_001a:  stloc.0
  IL_001b:  nop
  IL_001c:  ret
} // end of method Program::Main

在这段代码中,您可能会发现一个隐藏类c__DisplayClass1,在其中我们可以看到一个名为n:的uint32类型的公共字段

.field public uint32 n

方法<Main>b__0:

.method public hidebysig instance uint32 
    '<Main>b__0'() cil managed
{
  .maxstack  1
  .locals init ([0] uint32 CS$1$0000)
  IL_0000:  ldarg.0
  IL_0001:  ldfld      uint32 Utils.Program/'<>c__DisplayClass1'::n
  IL_0006:  call       uint32 Utils.Program::Fibonacci(uint32)
  IL_000b:  stloc.0
  IL_000c:  br.s       IL_000e
  IL_000e:  ldloc.0
  IL_000f:  ret
} // end of method '<>c__DisplayClass1'::'<Main>b__0'

它实际上调用CCD_ 7并传递CCD_。因此编译器将局部变量n提取到一个单独的类中;以及将lambda提取到此类的方法中。最后,看起来您将c__DisplayClass1.<Main>b__0分配给了Func<uint> fibN

函数:

Func<uint> fibN = () => Fibonacci(n);

可以重写如下,假设n是一个类变量:

private uint fibN() {
    return Fibonacci(n);
}

因此,fibN返回uint,但不需要输入参数。