C# 事件

C# 和 .NET 是支持事件驱动编程的,但它的处理需要委托实现来调度事件,所以事件和委托是紧密关联(耦合性高)。

事件是允许类或对象的某些状态发生改变时通知其它类或对象。

.NET 中的事件遵循观察者设计模式,常用的设计模式不熟悉的可以网上查查。

发送或引发事件的类称为发布者,接收或处理事件的类称为订阅者。

声明事件步骤

要在类中声明事件,首先必须声明事件的委托类型,如下:

public delegate void Notify();

其次,声明事件,如下:

public event Notify ProcessCompleted;

第三,调用事件,如下:

if(ProcessCompleted != null)
    ProcessCompleted();

//或者
//ProcessCompeleted?.Invoke();

只能在声明事件的类中调用事件。

第四,注册事件,如下:

sample.ProcessCompleted += Sample_ProcessCompeleted;

如果是要取消事件,如下:

sample.ProcessCompleted -= Sample_ProcessCompeleted;

完整代码:  

public class EventSample
{
    public delegate void Notify();

    public event Notify ProcessCompeleted;

    public void Start()
    {
        Console.WriteLine("开始作业");
        //业务逻辑

        //处理完毕后触发事件
        OnProcessCompeleted();
    }

    protected virtual void OnProcessCompeleted()
    {
        ProcessCompeleted?.Invoke();
        //判断是否订阅了
        //if (ProcessCompeleted != null)
        //    ProcessCompeleted();
    }
}

class Program
{
    static void Main(string[] args)
    {
        EventSample sample = new EventSample();
        sample.ProcessCompeleted += Sample_ProcessCompeleted;
        sample.Start();

        Console.ReadLine();
    }

    private static void Sample_ProcessCompeleted()
    {
        Console.WriteLine("处理完成");
    }
}

上面,Start() 方法最后一行调用了 OnProcessCompeleted() ,这引发了一个事件,通常,要引发事件,应使用名称定义受保护的虚拟方法 On<EventName> 。protected 和 virtual 使派生类能够覆盖引发事件的逻辑。但是,派生类应始终调用 On<EventName> 基类方法,以确保注册的委托接收事件。

OnProcessCompleted()方法调用委托 ProcessCompleted?.Invoke();。这会调用事件中注册的所有事件处理程序方法。

Program 类是 ProcessCompeleted 事件的订阅者。它使用 += 运算符向事件注册。Sample_ProcessCompeleted() 是处理事件方法且与 Notify 委托声明的一致。

内置 EventHandler 委托

.NET 还内置了两个常用的委托类型 EventHandler 和 EventHandler<TEventArgs> 。通常,任何事件都应包括两个参数:事件源和事件数据。EventHandler 主要用于不包含事件数据;对包含事件数据的使用 EventHandler<TEventArgs> 。

先看 EventHandler 的使用。

public class EventSample
{
    //public delegate void Notify();

    public event EventHandler ProcessCompeleted;

    public void Start()
    {
        Console.WriteLine("开始作业");
        //业务逻辑

        //处理完毕后触发事件
        OnProcessCompeleted(EventArgs.Empty);
    }

    protected virtual void OnProcessCompeleted(EventArgs e)
    {
        ProcessCompeleted?.Invoke(this, e);
    }
}

class Program
{
    static void Main(string[] args)
    {
        EventSample sample = new EventSample();
        sample.ProcessCompeleted += Sample_ProcessCompeleted;
        sample.Start();

        Console.ReadLine();
    }

    private static void Sample_ProcessCompeleted(object sender,EventArgs e)
    {
        Console.WriteLine("处理完成");
    }
}

上面代码中,Sample_ProcessCompeleted() 方法多了两个与 EventHandler 匹配的参数。此外,当我们在方法中使用引发事件时,this 作为发送者传递。另外,我们的事件不需要数据,所以使用 EventArgs.Empty 。

传递事件数据

大多数事件都会向订阅者发送一些数据。EventArgs 类是所有事件数据的基类。.NET 还包含了其它的内置事件数据类,如:SerialDataReceivedEventArgs 。它遵循以 EventArgs 结尾的命名方式。我们可以通过继承 EventArgs 来自定义事件数据。

public class ProcessCompeletedEventArgs : EventArgs
{
    public bool IsCompeleted { get; set; }

    /// <summary>
    /// 完成时间
    /// </summary>
    public DateTime CompeletedAt { get; set; }
}

public class EventSample
{
    //public delegate void Notify();

    public event EventHandler<ProcessCompeletedEventArgs> ProcessCompeleted;

    public void Start()
    {
        Console.WriteLine("开始作业");
        //业务逻辑

        ProcessCompeletedEventArgs e = new ProcessCompeletedEventArgs
        {
            IsCompeleted = true,
            CompeletedAt =DateTime.Now
        };

        //处理完毕后触发事件
        OnProcessCompeleted(e);
    }

    protected virtual void OnProcessCompeleted(ProcessCompeletedEventArgs e)
    {
        ProcessCompeleted?.Invoke(this, e);
    }
}
class Program
{
    static void Main(string[] args)
    {
        EventSample sample = new EventSample();
        sample.ProcessCompeleted += Sample_ProcessCompeleted;
        sample.Start();

        Console.ReadKey();
    }

    private static void Sample_ProcessCompeleted(object sender, ProcessCompeletedEventArgs e)
    {
        Console.WriteLine("IsCompeleted:{0},CompletedAt:{1}", e.IsCompeleted, e.CompeletedAt);

        Console.WriteLine("处理完成");
    }
}

 总结

我们总结下事件的一些要点:

  1. 事件是委托的封装,以防止委托的用户重置委托及其调用列表,并且只允许在调用列表中添加或删除目标

  2. 一些常用的事件尽量使用内置 EventHandler 或 EventHandler<TEventArgs>

  3. 发布者类引发一个事件(发布者确定何时引发事件),订阅者类注册一个事件并提供事件的处理方法(订阅者确定采取什么动作来响应)

  4. 处理事件的方法必须与委托声明的保持一致

  5. 使用 += 运算符注册事件;使用 -= 运算符取消订阅

  6. 尽量使用 EventHandler<TEventArgs> 来传递事件数据,TEventArgs 是泛型保证类型安全

  7. 可以继承 EventArgs 来自定义事件数据

  8. 事件可以声明为静态、虚拟、密封和抽象

  9. 接口可以包含事件

  10. 一个事件可以有多个订阅者

  11. 如果有多个订阅者,则同步调用事件处理程序。

 最后,祝大家学习愉快!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值