0Pricing
C# Academy · 课时

局部函数与 Lambda

在局部函数和 Lambda 之间进行选择。

局部函数与 Lambda 是 CoddyKit 上的免费 C# Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C# Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C# Academy 课程共包含 4 节课。

局部函数与匿名函数

局部函数和匿名函数都可以让您在方法内部定义小型函数。两者有许多相似之处,但在语法、功能和性能方面有所不同。选择合适的方式可以让代码更清晰、更高效。

编写辅助函数的两种方式

这里将同一个求平方辅助函数分别写成局部函数和赋给委托的匿名函数。两者会产生相同的结果。

using System;

public class Program
{
    public static void Main()
    {
        int SquareFn(int n) => n * n;       // local function
        Func<int, int> squareLambda = n => n * n; // lambda

        Console.WriteLine(SquareFn(4));
        Console.WriteLine(squareLambda(4));
    }
}

局部函数可以轻松实现递归

局部函数可以按名称调用自身。匿名函数在初始化期间不能引用自身的变量,因此使用匿名函数实现递归会比较棘手。

using System;

public class Program
{
    public static void Main()
    {
        // Clean recursion with a local function
        int Factorial(int n) => n <= 1 ? 1 : n * Factorial(n - 1);
        Console.WriteLine(Factorial(5));
    }
}

局部函数可以是泛型的

局部函数支持自己的类型参数。匿名函数不能是泛型的,因此对于可复用的类型化辅助函数,应选择局部函数。

using System;

public class Program
{
    public static void Main()
    {
        T First<T>(T[] items) => items[0]; // generic local function

        Console.WriteLine(First(new[] { 9, 8, 7 }));
        Console.WriteLine(First(new[] { "a", "b" }));
    }
}

性能:避免委托分配

赋给委托的匿名函数可能会分配委托对象;如果它捕获变量,还会分配闭包。直接调用局部函数可以避免这两种分配,这在高频循环中很重要。

using System;

public class Program
{
    public static void Main()
    {
        // Direct call, no delegate or closure allocation
        static int Add(int a, int b) => a + b;

        int total = 0;
        for (int i = 0; i < 5; i++) total = Add(total, i);
        Console.WriteLine(total);
    }
}

输出参数与引用参数

局部函数可以声明 out 和 ref 参数;通过常用的 Func/Action 委托实现的匿名函数则不能。这使得尝试解析辅助函数很适合用局部函数编写。

using System;

public class Program
{
    public static void Main()
    {
        bool TryGetFirstDigit(string s, out int digit)
        {
            digit = 0;
            foreach (var c in s)
                if (char.IsDigit(c)) { digit = c - '0'; return true; }
            return false;
        }

        if (TryGetFirstDigit("abc4", out int d))
            Console.WriteLine(d);
    }
}

拉姆达表达式作为内联参数更出色

当您需要将行为直接传递给 LINQ 的 Where 或 Select 等方法时,拉姆达表达式是最简洁、最易读的选择。

using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
    public static void Main()
    {
        var nums = new List<int> { 1, 2, 3, 4, 5, 6 };
        var evens = nums.Where(n => n % 2 == 0).Select(n => n * 10);
        Console.WriteLine(string.Join(", ", evens));
    }
}

两者都支持捕获

两种形式都可以捕获外层变量。两者的差异主要在语法和分配开销上,而不在于是否支持捕获。

using System;

public class Program
{
    public static void Main()
    {
        int bonus = 10;
        int WithBonusFn(int n) => n + bonus;     // captures
        Func<int, int> withBonusLambda = n => n + bonus; // captures

        Console.WriteLine(WithBonusFn(5));
        Console.WriteLine(withBonusLambda(5));
    }
}

确定赋值与顺序

局部函数可以在方法中声明之前调用;拉姆达表达式变量则必须先赋值才能使用。因此,局部函数的放置位置更加灵活。

using System;

public class Program
{
    public static void Main()
    {
        Console.WriteLine(Triple(4)); // allowed before declaration

        int Triple(int n) => n * 3;
    }
}

如何在两者之间选择

对于具有名称、需要复用、递归、泛型或处于热路径中的辅助逻辑,请使用局部函数。对于直接传递给其他方法的简短内联行为,请使用拉姆达表达式。两者都是工具,请根据意图进行选择。

using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
    public static void Main()
    {
        static bool IsPrime(int n)
        {
            if (n < 2) return false;
            for (int i = 2; i * i <= n; i++)
                if (n % i == 0) return false;
            return true;
        }

        var primes = Enumerable.Range(2, 20).Where(IsPrime);
        Console.WriteLine(string.Join(", ", primes));
    }
}

亲自尝试

使用递归局部函数实现核心逻辑,并使用拉姆达表达式实现内联 LINQ 投影,让每种构造都发挥其所长。

using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
    public static void Main()
    {
        // Local function: recursive, named, reusable
        static int DigitCount(int n) => Math.Abs(n) < 10 ? 1 : 1 + DigitCount(n / 10);

        var nums = new List<int> { 5, 42, 1000, 7, 88 };
        // Lambda: concise inline projection
        var report = nums.Select(n => n + " has " + DigitCount(n) + " digits");
        foreach (var line in report) Console.WriteLine(line);
    }
}

快速检查

比较这两种构造。

回顾

局部函数和拉姆达表达式有相似之处,但在一些关键方面有所不同。

  • 局部函数可以递归、使用泛型,并支持 out/ref。
  • 直接调用局部函数时,可以避免委托和闭包分配。
  • 拉姆达表达式作为传递给 LINQ 等方法的内联参数时最为简洁。
  • 请根据意图进行选择:是需要具有名称且可复用的辅助函数,还是简短的内联行为。

常见问题解答

「局部函数与 Lambda」课时是免费的吗?

是的 — 「局部函数与 Lambda」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C# Academy 课程的其余内容,请升级到 CoddyKit PRO。 C# Academy 课程共包含 4 节课。

「局部函数与 Lambda」这节课中我会学到什么?

在局部函数和 Lambda 之间进行选择。 你通过在浏览器中直接运行的动手代码来练习 C# Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C# Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C# Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「局部函数与 Lambda」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C# Academy 课中编写并运行代码吗?

能。每节 C# Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 声明局部函数
  2. 闭包与捕获变量
  3. 静态局部函数
  4. 局部函数与 Lambda
← 返回 C# Academy