什么是委托
委托 是C#中的一种引用类型 ,用于安全地封装方法 ,类似于C/C++中的函数指针,但它是面向对象、类型安全和可靠的。委托本质上是定义方法签名的类型,允许将方法作为参数传递或赋值给变量,实现方法的间接调用。
委托的核心特点
- 类型安全:委托确保方法签名匹配,避免了C/C++函数指针可能导致的类型错误
- 面向对象 :委托是.NET Framework中的类,派生自
System.Delegate - 引用类型:委托类型是密封的(sealed),不能继承
- 封装方法:委托对象可以引用一个或多个方法
委托的语法
声明委托
cs
public delegate 返回类型 委托名称(参数列表);
cs
// 声明一个委托:可以封装接受字符串参数、返回void的方法
public delegate void Callback(string message);
实例化委托
cs
// 定义方法
public static void DelegateMethod(string message)
{
Console.WriteLine(message);
}
// 实例化委托
Callback handler = DelegateMethod; // 将方法名赋值给委托
// 使用Lambda表达式实例化
Callback handler2 = (msg) => Console.WriteLine("Lambda: " + msg);
调用委托
cs
// 调用委托
handler("Hello World"); // 输出: Hello World
handler2("Hello from Lambda"); // 输出: Hello from Lambda
委托的用途
1. 作为回调方法
委托允许将方法作为参数传递,实现回调机制:
cs
public static void MethodWithCallback(int param1, int param2, Callback callback)
{
callback("The number is: " + (param1 + param2).ToString());
}
// 使用
MethodWithCallback(1, 2, handler); // 输出: The number is: 3
2. 事件处理
事件是委托的特殊应用,用于实现观察者模式:
cs
// 定义事件委托
public delegate void ClickEventHandler(object sender, EventArgs e);
// 事件发布者
public class Button
{
public event ClickEventHandler Clicked;
public void SimulateClick()
{
Console.WriteLine("按钮被点击了...");
Clicked?.Invoke(this, new EventArgs());
}
}
// 事件订阅者
public class Form
{
public Form(Button button)
{
button.Clicked += Button_Clicked;
}
private void Button_Clicked(object sender, EventArgs e)
{
Console.WriteLine("窗口收到通知:按钮被点击,执行响应逻辑!");
}
}
3. 多播委托
委托可以链接多个方法,实现多播调用:
cs
public class MethodClass
{
public void Method1(string message) { Console.WriteLine("Method1: " + message); }
public void Method2(string message) { Console.WriteLine("Method2: " + message); }
}
// 使用多播
var obj = new MethodClass();
Callback d1 = obj.Method1;
Callback d2 = obj.Method2;
Callback d3 = DelegateMethod;
// 链接委托
Callback allMethodsDelegate = d1 + d2;
allMethodsDelegate += d3;
// 调用所有方法
allMethodsDelegate("Hello");
// 输出:
// Method1: Hello
// Method2: Hello
// Hello World
C#内置委托
C#提供了常用的泛型委托类型,简化了常见场景的使用:
-
Action:无返回值的委托,支持不同参数数量
Action:无参数Action<T>:一个参数Action<T1, T2>:两个参数- ...
-
Func:有返回值的委托,支持不同参数数量和返回类型
Func<TResult>:无参数,返回TResultFunc<T, TResult>:一个参数,返回TResultFunc<T1, T2, TResult>:两个参数,返回TResult- ...
示例:
cs
// 使用Action
Action<string> print = (msg) => Console.WriteLine(msg);
print("Hello");
// 使用Func
Func<int, int, int> add = (a, b) => a + b;
int result = add(3, 5); // 8
委托与事件的关系
事件是基于委托实现的特殊机制,用于实现发布-订阅模式:
- 事件使用委托类型
- 事件只能通过
+=和-=操作符添加或移除方法 - 事件封装了委托,限制了外部直接调用委托
cs
// 事件声明
public event ClickEventHandler Clicked;
// 事件使用
button.Clicked += Form.Button_Clicked; // 订阅
button.Clicked -= Form.Button_Clicked; // 取消订阅
为什么需要委托
- 解耦:使组件之间松散耦合,提高代码可维护性
- 灵活性:允许在运行时动态决定调用哪个方法
- 代码复用:将方法作为参数传递,提高代码复用率
- 事件驱动:实现事件处理机制,如UI事件、异步操作完成通知
委托的演变
C#语言对委托功能持续演进:
- C# 2.0:引入匿名方法
- C# 3.0:引入Lambda表达式
- C# 10.0:增强Lambda表达式,允许自然类型推断
- C# 11.0:改进方法组到委托的转换
- C# 12.0:为Lambda表达式参数增加可选参数功能
总结
委托是C#中实现动态回调 与事件驱动 编程的核心机制,它使方法能够像数据一样被传递和使用。通过委托,我们可以编写出更加灵活、可扩展和可维护的代码,是面向对象编程中实现策略模式 和观察者模式的关键技术。