事件委托的核心概念与编程步骤
事件编程的基本要素,C#事件编程通常包含以下三个核心步骤:
1.定义委托 :约定事件处理方法的签名。
2.声明事件 :基于委托声明一个事件。
3.触发事件:在满足特定条件时调用事件。
在.NET中,标准事件模式通常包含以下组件:
事件委托:通常返回类型为void,并接受两个参数 - object sender(事件源)和派生自EventArgs的参数对象
事件参数:如需传递自定义数据,应创建继承自EventArgs的类
事件触发方法:通常命名为OnEventName,使用protected virtual修饰以便子类可以重写
事件委托示例
- 使用自定义委托的基本事件
以下示例展示了一个简单的角色受伤事件系统:
bash
// 定义事件委托
public delegate void DamageEventHandler(int damageAmount);
public class Player
{
// 声明事件
public event DamageEventHandler Damaged;
// 触发事件的方法
public void TakeDamage(int damageAmount)
{
OnDamaged(damageAmount);
}
protected virtual void OnDamaged(int damageAmount)
{
// 安全地触发事件(检查是否为null)
Damaged?.Invoke(damageAmount);
}
}
// 事件订阅者
public class DamageEffect
{
public void OnPlayerDamaged(int damageAmount)
{
Console.WriteLine($"角色受到 {damageAmount} 点伤害的效果");
}
}
// 使用示例
class Program
{
static void Main(string[] args)
{
Player player = new Player();
DamageEffect damageEffect = new DamageEffect();
// 订阅事件
player.Damaged += damageEffect.OnPlayerDamaged;
// 触发事件
player.TakeDamage(20);
}
}
- 使用标准EventHandler的温度监控系统
以下是一个更符合.NET标准的事件实现示例:
bash
using System;
// 自定义事件参数(传递数据)
public class TemperatureChangedEventArgs : EventArgs
{
public double CurrentTemperature { get; }
public TemperatureChangedEventArgs(double temperature)
{
CurrentTemperature = temperature;
}
}
// 事件发布者
public class TemperatureMonitor
{
// 使用泛型EventHandler声明事件
public event EventHandler<TemperatureChangedEventArgs> OnTemperatureExceeded;
private double _threshold;
public TemperatureMonitor(double threshold)
{
_threshold = threshold;
}
public void UpdateTemperature(double newTemperature)
{
if (newTemperature > _threshold)
{
// 触发事件
OnTemperatureExceeded?.Invoke(this,
new TemperatureChangedEventArgs(newTemperature));
}
}
}
// 事件订阅者
public class AlertSystem
{
public AlertSystem(TemperatureMonitor monitor)
{
// 订阅事件
monitor.OnTemperatureExceeded += HandleOverheat;
}
private void HandleOverheat(object sender, TemperatureChangedEventArgs e)
{
Console.WriteLine($"警报:温度超标!当前温度 {e.CurrentTemperature}°C");
}
}
// 使用示例
class Program
{
static void Main()
{
var monitor = new TemperatureMonitor(100); // 阈值设为100°C
var alert = new AlertSystem(monitor);
monitor.UpdateTemperature(99); // 不会触发
monitor.UpdateTemperature(105); // 触发事件,输出警报
}
}
- 杂志订阅发布系统(多事件示例)
以下示例展示了包含多个事件和自定义事件参数的复杂场景:
bash
using System;
// 自定义事件参数
public class PubEventArgs : EventArgs
{
public string MagazineName { get; }
public string PublishDate { get; }
public PubEventArgs(string magazineName, DateTime pubDate)
{
MagazineName = magazineName;
PublishDate = pubDate.ToString("yyyy-MM-dd");
}
}
// 发布者类
public class Publisher
{
// 声明多个事件
public event EventHandler<PubEventArgs> PubComputer;
public event EventHandler<PubEventArgs> PubLife;
protected virtual void OnPubComputer(PubEventArgs e)
{
PubComputer?.Invoke(this, e);
}
protected virtual void OnPubLife(PubEventArgs e)
{
PubLife?.Invoke(this, e);
}
public void IssueComputer(string magazineName, DateTime pubDate)
{
Console.WriteLine($"发行{magazineName}");
OnPubComputer(new PubEventArgs(magazineName, pubDate));
}
public void IssueLife(string magazineName, DateTime pubDate)
{
Console.WriteLine($"发行{magazineName}");
OnPubLife(new PubEventArgs(magazineName, pubDate));
}
}
// 订阅者类
public class Subscriber
{
private string _name;
public Subscriber(string name)
{
_name = name;
}
public void Receive(object sender, PubEventArgs e)
{
Console.WriteLine($"{e.PublishDate} {_name}已经收到{e.MagazineName}");
}
}
总结 事件与委托的关系:
事件是特殊的委托,它提供了更好的封装性,防止外部类直接触发事件
安全的事件触发模式:使用?.Invoke()可以安全地触发事件,避免空引用异常
事件订阅与取消:使用+=操作符订阅事件,使用-=操作符取消订阅
标准事件模式的重要性:遵循.NET框架的事件模式(使用EventHandler和EventArgs)可以提高代码的一致性和可维护性
典型应用场景:事件委托广泛应用于用户界面交互、异步操作通知、传感器数据监控和游戏状态变化等场景