1. 委托的核心概念
-
本质:
委托是一个类(System.Delegate
的派生类),封装了对一个或多个方法的引用。 -
作用:
解耦调用方和被调用方,实现动态绑定方法,支持灵活的回调机制。 -
关键特性:
-
类型安全:委托在编译时检查方法签名。
-
多播(Multicast):一个委托实例可以调用多个方法(通过
+
或+=
组合)。 -
异步支持:委托天然支持
BeginInvoke
/EndInvoke
异步调用(已逐渐被async/await
取代)。
-
2. 委托的声明与使用
(1) 定义委托类型
// 声明一个委托类型,定义方法的签名(参数和返回值)
public delegate void MyDelegate(string message);
-
委托类型需与方法签名一致(参数类型、返回值)。
(2) 实例化委托
// 普通方法
public void PrintMessage(string text)
{
Console.WriteLine(text);
}
// 实例化委托并绑定方法
MyDelegate delegateInstance = PrintMessage;
(3) 调用委托
delegateInstance("Hello, Delegate!"); // 输出:Hello, Delegate!
3. 多播委托(Multicast Delegate)
-
一个委托实例可以绑定多个方法,按添加顺序依次执行。
-
示例:
public void Method1(string msg) => Console.WriteLine($"Method1: {msg}"); public void Method2(string msg) => Console.WriteLine($"Method2: {msg}"); MyDelegate multiDelegate = Method1; multiDelegate += Method2; // 添加第二个方法 multiDelegate("Multi-test"); // 输出: // Method1: Multi-test // Method2: Multi-test
-
注意:如果委托有返回值,只有最后一个方法的返回值会被保留。
4. 委托与事件的关系
-
事件是对委托的封装:
事件内部通过委托实现,但仅允许声明类触发事件(Invoke
),外部只能订阅(+=
)或取消订阅(-=
)。 -
示例:
// 事件基于委托 public event MyDelegate MyEvent; // 触发事件(只能在声明类内部调用) private void RaiseEvent(string message) { MyEvent?.Invoke(message); }
5. 内置委托类型
C# 提供了通用的委托类型,避免重复定义:
(1) Action
-
无返回值的方法:
Action<string> actionDelegate = msg => Console.WriteLine(msg); actionDelegate("Action!"); // 输出:Action!
(2) Func
-
有返回值的方法:
Func<int, int, int> add = (a, b) => a + b; int result = add(3, 5); // result = 8
(3) Predicate
-
返回
bool
的方法(常用于集合筛选):Predicate<int> isEven = num => num % 2 == 0; bool check = isEven(4); // check = true
6. 委托的高级用法
(1) 匿名方法与 Lambda 表达式
简化委托实例化:
MyDelegate anonymousDelegate = delegate(string msg)
{
Console.WriteLine($"匿名方法:{msg}");
};
// Lambda 表达式(更简洁)
MyDelegate lambdaDelegate = msg => Console.WriteLine($"Lambda:{msg}");
(2) 协变与逆变(Covariance/Contravariance)
-
协变:委托的返回值可以是派生类型(子类 → 父类)。
-
逆变:委托的参数可以是基类型(父类 → 子类)。
// 协变示例(返回值)
delegate Animal GetAnimal();
GetAnimal getDog = () => new Dog(); // Dog 是 Animal 的子类
// 逆变示例(参数)
delegate void ProcessDog(Dog dog);
ProcessDog processAnimal = (Animal a) => { }; // Animal 是 Dog 的基类
7. 实际应用场景
-
事件处理:按钮点击、温度报警等。
-
回调机制:异步操作完成后通知调用方。
-
LINQ 查询:
Where
、Select
等方法接受委托参数。 -
策略模式:动态切换算法逻辑。