Files
My-Notes/笔记/CSharp/进阶/委托.md
T
2026-08-09 12:41:53 +08:00

7.7 KiB
Raw Blame History

委托

概念: 委托是==可以引用方法的类型== 可以理解为“函数的容器”或“存方法的变量”

作用:

  1. 把方法赋值给变量
  2. 把方法作为参数传递
  3. 让一个地方可以调用多个方法
  4. 为事件、匿名函数、lambda 提供基础

简单理解: 普通变量存数据 委托变量存“符合条件的方法”


通常用法

  1. 作为类的成员,保存回调方法
  2. 作为方法参数,让调用者决定具体执行什么逻辑
  3. 同时绑定多个方法,实现多播调用
  4. 配合 ActionFunc、匿名函数和 lambda 使用

实际开发中: 自定义委托仍然会用到 但很多简单场景更常使用系统自带的 ActionFunc


语法

关键字:

delegate

定义委托:

访问修饰符 delegate 返回值类型 委托名(参数列表);

示例:

public delegate void MyDelegate(string message);

说明: MyDelegate 只能保存: 参数是 string 返回值是 void 的方法


基础案例

using System;

public delegate void MyDelegate(string message);

class Program
{
	static void PrintMessage(string message)
	{
		Console.WriteLine(message);
	}

	static void Main(string[] args)
	{
		MyDelegate del = PrintMessage;
		del("你好,委托");
	}
}

输出:

你好,委托

理解:

  1. MyDelegate 规定了方法的格式
  2. PrintMessage 的参数和返回值符合这个格式
  3. 所以可以赋值给 del
  4. 调用 del(...),本质上就是调用 PrintMessage(...)

方法必须匹配委托格式

public delegate int Calculate(int a, int b);

static int Add(int a, int b)
{
	return a + b;
}

Calculate calculate = Add;
Console.WriteLine(calculate(10, 20));

正确匹配: 参数数量一致 参数类型一致 返回值类型一致

错误示例:

static void Print(int a, int b)
{
}

// Calculate calculate = Print;

原因: Calculate 要求返回 int Print 的返回值是 void 两者不匹配


委托的赋值和调用

赋值:

MyDelegate del = PrintMessage;

调用:

del("hello");

也可以使用 Invoke

del.Invoke("hello");

通常写法: 直接写 del(...) 更常见 Invoke(...) 的语义更明确


委托可以作为参数

作用: 把“具体要做什么”交给调用者决定

using System;

public delegate void HandleNumber(int number);

class Program
{
	static void Process(int number, HandleNumber handler)
	{
		handler(number);
	}

	static void PrintNumber(int number)
	{
		Console.WriteLine("数字:" + number);
	}

	static void PrintDouble(int number)
	{
		Console.WriteLine("两倍:" + number * 2);
	}

	static void Main(string[] args)
	{
		Process(10, PrintNumber);
		Process(10, PrintDouble);
	}
}

输出:

数字:10
两倍:20

理解: Process 不关心具体处理方式 只要求传进来的方法符合 HandleNumber 的格式


多播委托

一个委托变量可以同时绑定多个方法:

using System;

public delegate void MyDelegate();

class Program
{
	static void Method1()
	{
		Console.WriteLine("执行方法1");
	}

	static void Method2()
	{
		Console.WriteLine("执行方法2");
	}

	static void Main(string[] args)
	{
		MyDelegate del = Method1;
		del += Method2;

		del();
	}
}

输出:

执行方法1
执行方法2

取消绑定:

del -= Method2;

说明:

  1. += 用来添加方法
  2. -= 用来移除方法
  3. 调用时会按添加顺序依次执行
  4. 多播委托最适合返回值为 void 的情况

有返回值的多播委托

public delegate int Calculate();

static int Method1()
{
	return 1;
}

static int Method2()
{
	return 2;
}

Calculate calculate = Method1;
calculate += Method2;

int result = calculate();
Console.WriteLine(result);

输出:

2

说明: 两个方法都会执行 但委托调用的最终返回值,只会保留最后一个方法的返回值

所以: 多播委托通常更适合 void 返回值


空委托要先判断

错误示例:

MyDelegate del = null;

// del();

原因: 委托变量是引用类型 没有绑定方法时可能为 null

常见写法:

if (del != null)
{
	del();
}

更简洁的写法:

del?.Invoke();

说明: ?. 会先判断 del 是否为 null 不为 null 才调用 Invoke()


Action

Action 是系统自带的委托类型: ==无返回值==

无参:

Action action = PrintHello;
action();

static void PrintHello()
{
	Console.WriteLine("Hello");
}

有参数:

Action<string> print = PrintMessage;
print("你好");

static void PrintMessage(string message)
{
	Console.WriteLine(message);
}

说明: Action 后面的泛型参数表示方法参数类型 它的返回值始终是 void


Func

Func 是系统自带的泛型委托类型: ==有返回值==

Func<int, int, int> add = Add;

int result = add(10, 20);
Console.WriteLine(result);

static int Add(int a, int b)
{
	return a + b;
}

说明:

Func<参数1类型, 参数2类型, 返回值类型>

上面的:

Func<int, int, int>

表示: 前两个 int 是参数类型 最后一个 int 是返回值类型


自定义委托、Action、Func 的区别

对比点 自定义委托 Action Func
是否需要自己声明 需要 不需要 不需要
返回值 自己定义 必须是 void 必须有返回值
参数 自己定义 可有多个 可有多个
常见用途 语义明确的回调 简单无返回值操作 简单有返回值操作

实际使用建议:

  1. 简单无返回值回调,优先考虑 Action
  2. 简单有返回值回调,优先考虑 Func
  3. 需要清晰业务语义时,可以定义自己的委托类型

和事件的关系

委托: 可以在类外部赋值 也可以在类外部直接调用

事件: 是对委托的进一步封装 类外部只能订阅和取消订阅 不能直接调用事件

可以和事件一起理解: 委托负责“存方法和调用方法” 事件负责“更安全地对外发布通知”


注意

  1. 委托是一种引用类型
  2. 委托变量只能保存签名匹配的方法
  3. 签名主要看参数和返回值
  4. 委托可以绑定一个或多个方法
  5. += 添加方法,-= 移除方法
  6. 调用可能为 null 的委托前要先判断
  7. Action 无返回值,Func 有返回值
  8. 自定义委托不能只靠返回值不同来重名

易错点

  1. 委托不是方法本身,而是“引用方法的变量”
  2. 委托类型和方法签名不匹配时,不能赋值
  3. Add+= 不一样,委托绑定方法用 +=
  4. 多播委托有返回值时,只能拿到最后一个方法的返回值
  5. del?.Invoke() 可以避免空引用异常

一句话记忆

==委托就是一种可以存方法、传方法、调方法的类型。==


面试/复习时怎么说

可以这样答:

“委托是一种引用方法的类型,可以把符合指定签名的方法赋值给委托变量,再通过委托统一调用。
它可以作为参数传递,也可以绑定多个方法,常用于回调和事件机制。
实际开发中,简单场景通常使用系统自带的 ActionFunc。”


引用:

  1. Microsoft Learn: Delegates
  2. Microsoft Learn: Action Delegate
  3. Microsoft Learn: Func Delegate

#委托 #delegate #Action #Func #进阶