委托(Delegate)是C#中一种特殊的类型,它用于封装方法的引用。委托可以看作是类型安全的函数指针,允许你将方法作为参数传递给其他方法、从方法返回方法或者存储在变量中以备后用。委托在事件处理、回调函数和异步编程等场景中非常有用。
1. 定义委托类型
public delegate void MyDelegate(string message);
这行代码定义了一个名为 MyDelegate
的委托类型,它可以引用任何具有 void
返回类型并接受一个 string
参数的方法。
2. 创建委托实例并关联方法
class Program
{
// 定义一个符合委托签名的方法
public static void PrintMessage(string message)
{
Console.WriteLine($"消息: {message}");
}
static void Main(string[] args)
{
// 创建委托实例,并将其与 PrintMessage 方法关联
MyDelegate del = new MyDelegate(PrintMessage);
// 或者更简洁地使用 lambda 表达式
MyDelegate delLambda = (msg) => Console.WriteLine($"消息: {msg}");
// 调用委托
del("Hello, World!");
delLambda("Hello from Lambda!");
}
}
输出:
消息: Hello, World!
消息: Hello from Lambda!
委托允许你将一个方法作为参数传递给另一个方法,从而实现在特定条件下或操作完成后调用该方法的能力。这种模式称为回调。
using System;
public delegate void FileProcessCallback(string message);
class Program
{
static void Main()
{
string filePath = "example.txt";
ProcessFile(filePath, OnFileProcessed);
}
static void ProcessFile(string path, FileProcessCallback callback)
{
// 模拟文件处理逻辑
Console.WriteLine($"正在处理文件: {path}");
// 文件处理完成后调用回调
callback("文件处理已完成!");
}
static void OnFileProcessed(string message)
{
Console.WriteLine(message);
}
}
callback("文件处理已完成!");
是调用委托实例 callback
的方式。这行代码的作用是触发与 callback
关联的方法,并将字符串 "文件处理已完成!"
作为参数传递给该方法。
委托是实现事件驱动编程模型的基础。通过定义事件和订阅事件处理程序,对象可以在某些状态变化时通知其他对象,而无需直接依赖这些对象。
using System;
public class Button
{
// 定义一个事件
public event EventHandler Click;
public void OnClick()
{
Console.WriteLine("按钮被点击了");
Click?.Invoke(this, EventArgs.Empty);
}
}
class Program
{
static void Main()
{
var button = new Button();
// 订阅事件
button.Click += Button_Click;
// 模拟点击按钮
button.OnClick();
}
private static void Button_Click(object sender, EventArgs e)
{
Console.WriteLine("处理按钮点击事件");
}
}
Click
:这里假设Click
是一个事件(Event)。在C#中,事件通常用来通知其他对象某些事情发生了。?.
:这是空条件运算符(Null-conditional operator),它是在C# 6.0中引入的。这个运算符允许你安全地调用方法或访问属性、事件等成员,即使对象是null也不会抛出异常。如果左侧的操作数是null,则操作停止并且整个表达式的值为null。Invoke
:这是委托(Delegate)的一个方法,用来立即执行订阅了该事件的所有方法。换句话说,它触发了事件,所有订阅了Click
事件的监听者都会被通知到,并且会执行相应的事件处理代码。(this, EventArgs.Empty)
:这里是传递给事件处理程序的参数。this
通常指的是当前实例,即触发事件的对象。EventArgs.Empty
表示没有特定的事件数据要传递,或者说是使用了一个空的事件参数。Click
事件,并且Click
不是null,那么就调用Invoke
方法来触发这个事件,同时传递当前对象和一个空的事件参数给所有的事件处理程序。委托可以链接多个方法,形成一个多播委托。当调用这个委托时,所有链接的方法都会被依次执行。这在需要同时触发多个动作的情况下非常有用。
using System;
public delegate void MyDelegate(string message);
class Program
{
public static void Method1(string message)
{
Console.WriteLine($"Method1: {message}");
}
public static void Method2(string message)
{
Console.WriteLine($"Method2: {message}");
}
static void Main()
{
MyDelegate del = Method1;
del += Method2;
del("Calling multiple methods via delegate.");
}
}
事件是基于委托的。委托是一种类型安全的函数指针,它可以引用一个或多个方法。定义事件的第一步是声明一个委托。
public delegate void MyEventHandler(object sender, EventArgs e);
事件是对委托的封装,它提供了对事件处理程序的添加和移除功能。事件只能在其声明的类内部触发。
public event MyEventHandler MyEvent;
首先定义一个委托,该委托将作为事件处理程序的签名。
public delegate void NotifyEventHandler(object sender, EventArgs e);
在类中声明一个事件,通常使用上述定义的委托类型。
public class Publisher
{
// 声明事件
public event NotifyEventHandler NotifyEvent;
// 触发事件的方法
protected virtual void OnNotify(EventArgs e)
{
NotifyEvent?.Invoke(this, e); // 使用空合并运算符确保线程安全
}
}
其他类可以通过注册事件处理程序来订阅事件。
public class Subscriber
{
private Publisher _publisher;
public Subscriber(Publisher publisher)
{
_publisher = publisher;
// 订阅事件
_publisher.NotifyEvent += HandleNotify;
}
private void HandleNotify(object sender, EventArgs e)
{
Console.WriteLine("事件已触发!");
}
}
当特定条件满足时,发布者类可以触发事件,通知所有订阅者。
public class Publisher
{
// ... 其他代码
public void DoSomething()
{
// 模拟一些操作
Console.WriteLine("执行了一些操作...");
// 触发事件
OnNotify(EventArgs.Empty);
}
}
using System;
// 定义一个简单的事件处理程序,不携带额外数据
public class Button
{
// 声明一个事件,这里我们使用内置的EventHandler委托
public event EventHandler Clicked;
// 模拟按钮被点击的方法
public void SimulateClick()
{
Console.WriteLine("按钮被点击了...");
// 触发事件
OnClick();
}
// 触发Clicked事件的方法
protected virtual void OnClick()
{
// 使用?.操作符确保在没有订阅者时不会抛出异常
Clicked?.Invoke(this, EventArgs.Empty);
}
}
// 订阅者类,例如窗体或控制台应用程序的一部分
public class Form
{
private readonly Button _button;
// 构造函数中订阅按钮的点击事件
public Form(Button button)
{
_button = button;
_button.Clicked += HandleButtonClick; // 订阅事件
}
// 事件处理方法
private void HandleButtonClick(object sender, EventArgs e)
{
Console.WriteLine("响应按钮点击:显示消息框!");
}
}
// 程序入口
class Program
{
static void Main(string[] args)
{
// 创建按钮实例
var button = new Button();
// 创建窗体实例,并传入按钮实例(订阅按钮的点击事件)
var form = new Form(button);
// 模拟按钮点击
button.SimulateClick();
Console.ReadLine(); // 阻塞主线程以便查看输出结果
}
}
using System;
// 1. 定义一个自定义委托,它将作为事件的基础
public delegate void NotificationHandler(string message);
// 2. 发布者类 - Notifier
public class Notifier
{
// 3. 声明一个基于自定义委托的事件
public event NotificationHandler Notify;
// 4. 触发事件的方法
public void TriggerNotification(string message)
{
Console.WriteLine($"正在触发通知: {message}");
// 使用?.操作符确保在没有订阅者时不会抛出异常
Notify?.Invoke(message);
}
}
// 5. 订阅者类 - Listener
public class Listener
{
private readonly Notifier _notifier;
// 构造函数中订阅通知事件
public Listener(Notifier notifier)
{
_notifier = notifier;
_notifier.Notify += HandleNotification; // 订阅事件
}
// 6. 事件处理方法
private void HandleNotification(string message)
{
Console.WriteLine($"收到通知: {message}");
}
// 不再需要监听时移除事件处理程序(防止内存泄漏)
public void Unsubscribe()
{
_notifier.Notify -= HandleNotification;
}
}
// 程序入口
class Program
{
static void Main(string[] args)
{
// 创建通知者实例
var notifier = new Notifier();
// 创建监听者实例,并传入通知者实例(订阅通知事件)
var listener = new Listener(notifier);
// 模拟触发通知
notifier.TriggerNotification("欢迎来到我们的平台!");
// 如果不再需要监听者,记得取消订阅
// listener.Unsubscribe();
Console.ReadLine(); // 阻塞主线程以便查看输出结果
}
}