什么是事件?
定义
- 事件是一种特殊的委托,用于在某一动作发生时通知其他对象。
- 它允许一个对象向多个监听者广播消息。
用途
- 实现发布-订阅模式,主要用于解耦对象之间的交互,不同模块能动态响应特定事件。
和委托关系
- 委托是事件的基础,它定义了事件处理器的签名。事件是基于委托的封装和扩展。
事件的组成部分
- 事件声明:在类中定义事件,通常使用event关键字。
- 事件触发:在某个动作完成后,引发事件。
- 事件订阅:外部对象注册方法来响应事件。
基本语法
1. 定义事件
public delegate void NotifyEventHandler(object sender, EventArgs e);
public class Process
{
// 使用委托类型定义事件
public event NotifyEventHandler ProcessCompleted;
public void StartProcess()
{
Console.WriteLine("Process started.");
// 模拟过程完成后引发事件
OnProcessCompleted(EventArgs.Empty);
}
protected virtual void OnProcessCompleted(EventArgs e)
{
ProcessCompleted?.Invoke(this, e);
}
}
2. 订阅和触发事件
public class Program
{
public static void Main()
{
Process process = new Process();
// 订阅事件
process.ProcessCompleted += Process_ProcessCompleted;
process.StartProcess();
}
private static void Process_ProcessCompleted(object sender, EventArgs e)
{
Console.WriteLine("Process completed event received.");
}
}
说明:
- ProcessCompleted事件是在OnProcessCompleted方法中触发的。
- Process_ProcessCompleted是事件处理器,当事件被触发时会被调用。
高级主题
内置事件处理器
- EventHandler:这是C#提供的标准事件处理器委托类型,常用于无数据或简单数据的事件:
public event EventHandler ProcessCompleted;
- EventHandler<TEventArgs>:用于传递附加信息:
public class CustomEventArgs : EventArgs
{
public string Message { get; set; }
}
public event EventHandler<CustomEventArgs> ProcessCompletedWithMessage;
使用内置EventHandler
public class SimpleProcess
{
public event EventHandler ProcessCompleted;
public void CompleteProcess()
{
Console.WriteLine("Completing process...");
ProcessCompleted?.Invoke(this, EventArgs.Empty);
}
}
自定义事件参数
- 如果需要传递额外的数据,可以创建自定义的事件参数类。
public class DownloadEventArgs : EventArgs
{
public string FileName { get; set; }
public long FileSize { get; set; }
}
public class DownloadManager
{
public event EventHandler<DownloadEventArgs> DownloadCompleted;
public void CompleteDownload(string fileName, long fileSize)
{
Console.WriteLine($"Download completed: {fileName}, Size: {fileSize}");
OnDownloadCompleted(new DownloadEventArgs { FileName = fileName, FileSize = fileSize });
}
protected virtual void OnDownloadCompleted(DownloadEventArgs e)
{
DownloadCompleted?.Invoke(this, e);
}
}
事件的多播特性
事件是基于委托的,因此支持多播,即多个订阅者可以同时接收同一事件通知。
public static void HandleSuccess(object sender, EventArgs e)
{
Console.WriteLine("Success handler executed.");
}
public static void Main()
{
SimpleProcess sp = new SimpleProcess();
// 多个方法订阅同一事件
sp.ProcessCompleted += Process_ProcessCompleted;
sp.ProcessCompleted += HandleSuccess;
sp.CompleteProcess();
}
实践习题
1.创建一个类DownloadManager,定义一个DownloadCompleted事件。在下载完成后触发此事件,并在主程序中订阅和处理该事件。
using System;
public class DownloadManager
{
public event EventHandler DownloadCompleted;
public void StartDownload()
{
Console.WriteLine("Starting download...");
// Simulate download completion
OnDownloadCompleted(EventArgs.Empty);
}
protected virtual void OnDownloadCompleted(EventArgs e)
{
DownloadCompleted?.Invoke(this, e);
}
}
public class Program
{
public static void Main()
{
DownloadManager dm = new DownloadManager();
// 订阅事件
dm.DownloadCompleted += Download_Completed;
dm.StartDownload();
}
private static void Download_Completed(object sender, EventArgs e)
{
Console.WriteLine("Download completed event received.");
}
}
2.修改上述DownloadManager,使得DownloadCompleted事件携带下载的文件名和大小信息。
using System;
public class DownloadEventArgs : EventArgs
{
public string FileName { get; set; }
public long FileSize { get; set; }
}
public class DownloadManager
{
public event EventHandler<DownloadEventArgs> DownloadCompleted;
public void StartDownload(string fileName, long fileSize)
{
Console.WriteLine($"Starting download of {fileName}...");
// Simulate download completion
OnDownloadCompleted(new DownloadEventArgs { FileName = fileName, FileSize = fileSize });
}
protected virtual void OnDownloadCompleted(DownloadEventArgs e)
{
DownloadCompleted?.Invoke(this, e);
}
}
public class Program
{
public static void Main()
{
DownloadManager dm = new DownloadManager();
// 订阅事件
dm.DownloadCompleted += Download_Completed;
dm.StartDownload("example.txt", 1024);
}
private static void Download_Completed(object sender, DownloadEventArgs e)
{
Console.WriteLine($"Download completed: {e.FileName}, Size: {e.FileSize}");
}
}
以上内容涵盖了如何定义、使用和扩展事件。掌握这些知识能够有效地编写模块化、解耦的代码。如果有其他问题或需要进一步讲解,请随时告诉我!