C# 委托和事件

之前写了一个狮子捉动物的例子,传送门:C# 发布-订阅模式

在那个例子中,用到了委托和事件,这里对例子里的代码进行详细解说,加深自己的理解。

首先,在公共部分定义一个委托:

public delegate void FindEventHandler(string animals);
// 可以看出这个委托是带有一个 string 类型参数的

然后我们分析一下狮子类:

public class 狮子
{
    // 基于上面定义的委托定义了一个事件
    public event FindEventHandler FindEvent;

    public void Find(string animals)
    {
       Console.WriteLine("狮子发现了{0}", animals);
       if (FindEvent != null)
       {
          FindEvent(animals);
       }
    }
}

在狮子类中,定义了一个事件 FindEvent,并且在 Find 方法中触发了该事件。在触发事件之前,为什么要判断事件是否为不空呢?这个后面解释。

接下来我们看一下动物类,以 A 为例:

public class A
{
    public A(狮子 狮子)  //A 的构造函数
    { 
        狮子.FindEvent += new FindEventHandler(a_FindEvent);//订阅发现事件
    }

    void a_FindEvent(string animals)
    {
        if(animals.Contains("A"))
        {
            Run();
        }
    }

    public void Run() 
    {
        Console.WriteLine("我是 A,被狮子发现了,我要跑了"); 
    }
}

在 A类 的构造函数中,接收了一个狮子类参数,没错,该形参的数据类型就是类。然后在构造函数中把方法 a_FindEvent 注册到了该类的事件上,如果没人向 FindEvent  注册,则 FindEvent 事件就为 null,执行就会报错,这就是为什么狮子类中触发事件的时候先判断了一下 FindEvent  事件是否为空。

注册了之后,只要 FindEvent  事件触发,就会自动执行 a_FindEvent  方法。

然后我们看一下主函数:

static void Main(string[] args)
{
    狮子 狮子 = new 狮子();

    A a = new A(狮子);
    B b = new B(狮子);

    狮子.Find("A");

    狮子.Find("B");

    狮子.Find("AB");

    Console.ReadLine();
    // 由于A和B订阅了狮子的事件,所以无需任何代码,A和B均会按照约定进行动作。
}

先实例化了一个狮子,然后把狮子丢在了大草原,动物 A 和 B 感受到了狮子的杀气(接收了狮子类),狮子发现 A ,A 跑;狮子发现 B ,B 跑;狮子发现 A、B ,A、B 都跑。

 

至此整个流程已经走通了,下面,再看看 类、委托、事件、方法到底是怎么联动的。

目前的理解如下图所示,委托就是一个指针,存储着事件的地址,方法注册到事件就是把方法的地址添加到了事件地址的后面,所以事件触发之后,所有注册到事件的方法就按照地址顺序依次执行了。

肯定是按照注册顺序(地址顺序)执行的,因为我调换过 A、B 实例化的顺序,执行顺序也就相应的调换了。

delegate

不使用 if…else,而使用这种模式,目的就是实现代码解耦,提高复用性、扩展性,这才是面向对象编程嘛!

发表评论

Powered by WordPress | Theme Revised from Doo

苏ICP备18047621号

Copyright © 2017-2024 追光者博客