目录

C# 委托 (Delegate) 深度解析

委托是 C# 中一种非常重要的引用类型,它是函数式编程在 C# 中的基础。

1. 简介

关键字:delegate (读音: /'dɛlɪɡət/)

核心概念

通俗理解:委托就像是一个“办事处代表”。你定义了这个代表能办什么事(比如能接收两个整数,返回一个整数)。任何符合这个标准的具体办事员(具体方法),都可以被指派给这个代表去执行任务。

2. 委托的使用步骤

使用自定义委托通常分为三步:

  1. 定义 (Define):像定义类一样,在类外部(或内部)声明委托类型。
  2. 实例化 (Instantiate):创建委托对象,并指向一个具体的方法。
  3. 调用 (Invoke):像调用函数一样调用委托对象。
// 1. 声明委托 (规定了必须是:两个int参数,返回bool)
public delegate bool CompareDelegate(int a, int b);
 
class Program
{
    static void Main()
    {
        // 2. 实例化委托,指向 IsGreater 方法
        // 注意:这里只写方法名,不要带括号()
        CompareDelegate compare = IsGreater;
 
        // 3. 调用委托
        bool result = compare(5, 3);
        Console.WriteLine($"Is 5 greater than 3? {result}"); 
    }
 
    // 具体方法:签名必须与委托一致
    static bool IsGreater(int a, int b)
    {
        return a > b;
    }
}

3. 委托应用场景举例

案例 1:逻辑解耦 (字符串过滤器)

委托允许我们将判断逻辑从主流程中剥离出来。

using System;
 
// 定义委托:接收 string,返回 bool
public delegate bool StringFilter(string input);
 
class Program
{
    static void Main()
    {
        // 这里的逻辑是可以动态替换的
        StringFilter filter = IsLongEnough;
 
        bool result = filter("Hello, World!");
        Console.WriteLine($"Is 'Hello, World!' long enough? {result}"); 
    }
 
    static bool IsLongEnough(string input)
    {
        return input.Length >= 10;
    }
}

案例 2:跨类调用

如果委托需要指向另一个类的方法,需要先实例化那个类。

class Program
{
    // 自定义委托类型
    public delegate int MathOpDelegate(int a, int b); 
 
    static void Main(string[] args)
    {
        // 1. 实例化包含方法的类
        Calculator calc = new Calculator();
 
        // 2. 委托指向该实例的成员方法
        MathOpDelegate myDelegate = calc.Multiply; // 注意:不要加括号()
 
        // 3. 执行委托
        int result = myDelegate(5, 7);
 
        Console.WriteLine($"结果: {result}"); // 输出 35
    }
}
 
class Calculator
{
    public int Multiply(int a, int b)
    {
        return a * b; 
    }
}

4. 系统预定义委托 (Action & Func)

为了避免每次使用委托都要先写 `public delegate …`,C# 提供了两个通用的泛型委托。

委托类型 返回值 用途 格式示例
Action 无 (void) 执行动作,不需结果 Action<T1, T2>
Func 有 (TResult) 计算并返回结果 Func<T1, T2, TResult>

Action 委托 (无返回值)

`Action` 后面尖括号里的类型全是输入参数

static void Main()
{
    // Action<string> 表示:接收一个 string 参数,无返回值
    Action<string> print = PrintMessage;
 
    print("Hello, System Delegate!");
}
 
static void PrintMessage(string message)
{
    Console.WriteLine(message);
}

Func 委托 (有返回值)

`Func` 后面尖括号里,最后一个类型永远是返回值类型,前面的都是输入参数类型。

static void Main()
{
    // Func<int, int, int> 表示:
    // 输入参数1: int
    // 输入参数2: int
    // 返回值: int
    Func<int, int, int> addFunc = Add;
 
    int sum = addFunc(3, 4);
    Console.WriteLine($"3 + 4 = {sum}");
}
 
static int Add(int a, int b)
{
    return a + b;
}

5. 匿名方法与 Lambda 表达式

有时我们只需要一个简单的逻辑,专门写一个静态函数太麻烦,这时可以使用匿名方法。

匿名方法 (C# 2.0 写法)

在实例化委托时,直接使用 `delegate` 关键字定义方法体。

public delegate int MathDelegate(int a, int b); 
 
static void Main(string[] args)
{
    // 直接内联定义逻辑,没有方法名
    MathDelegate multiply = delegate (int a, int b)
    {
        return a * b; 
    };
 
    int result = multiply(5, 7);
    Console.WriteLine(result);
}

知识拓展:Lambda 表达式 (C# 3.0+ 推荐写法)

现代 C# 开发中,几乎不再使用 `delegate (…) {}` 的匿名方法写法,而是使用更简洁的 Lambda 表达式 (`⇒`)。

static void Main(string[] args)
{
    // 这里的 (a, b) => a * b 等同于上面的匿名方法
    // => 读作 "goes to"
    Func<int, int, int> multiply = (a, b) => a * b;
 
    int result = multiply(5, 7);
    Console.WriteLine(result);
}

总结

  1. 定义:委托是方法的容器,可以把方法当参数传递。
  2. 自定义:使用 `delegate` 关键字定义签名。
  3. 系统内置
    1. `Action`: 无返回值。
    2. `Func`: 有返回值(最后一个泛型参数是返回类型)。
  4. 进化:从 `自定义委托` → `Action/Func` → `匿名方法` → `Lambda表达式`,代码越来越简洁。