首页 > 代码库 > C#事件

C#事件

今天来说一下C#的事件,说起事件不得不提委托,回调函数。其实这三者最本质的方面就是委托(函数指针)的运用,委托只是最基础的部分,定义了一个可以指向其他方法(函数) 的对象(简单理解就是一个指针变量)。其实很多帖子都谈到委托,回调函数和事件,但是都讲的很笼统,大神的理解固然深刻,但是对于初学者不易理解。委托的理解可以如上述所说,而回调函数则可以理解为一个方法在运行时调用了另一个方法,即它的入口参数中需要另外一个方法。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CallBack
{
    /// <summary>
    /// 通过sayhello方法调用hello方法,看似多次一举,其实代表了一种思路,即
    /// 把方法的行为与行为主体(本例中为name)分开
    /// </summary>
    /// <param name="h"></param>
    public delegate void newDelegate(string h);
    class Program
    {
        static void Main(string[] args)
        {
            SayHello("Andy", Hello);
            Console.ReadKey();
        }

        //调用函数
        static void SayHello(string name,newDelegate Hello)
        {
            Hello(name);
        }
        //回调函数
        static void Hello(string name)
        {
            Console.WriteLine(name + "你好!");
        }
    }
}

回调函数与事件是以委托为基础的,事件与回调函数在本质上都属于委托的应用,所以在本质上两者并没有太大界限,在很多解释回调函数的例子中,由于写的比较复杂,其实已经属于事件机制。所谓事件其实也是一个方法调用另一个方法。对事件进行细分流程可以这样理解:

1、首先要发布事件

      public delegate void reactEventhander();//定义一个委托
      //此处event可以不加,程序依旧可以运行,只是在类外部可以对事件进行修改,增加event可以避免
      public event reactEventhander RegularReact;//发布两个事件
      public event Eventhander MagicReact;

2、定义事件触发的条件(也可以无条件触发)

        //定义事件触发的条件
        //攻击者发动普通攻击时,被攻击者的反应
        public void RegularAttack()
        {
            Console.WriteLine("发起了普通攻击!");
            if(RegularReact!=null)//判断事件是否被订阅
            {
                RegularReact();
            }
        }

        public void MagciAttack()
        {
            Console.WriteLine("发起了魔法攻击!");
            if (RegularReact != null)//判断事件是否被订阅
            {
                MagicReact();
            }
        }

3、事件被订阅

        public Enemy1(Attacker a)
        {
            //Enemy1对事件进行了订阅,遭受攻击时反应
            a.RegularReact += new reactEventhander(a_RegularAttacek);
            a.MagicReact += new reactEventhander(a_MagciAttacek);
        }

4、最后事件发生

通过下边例子说明。此例子来模拟两个小怪(enemy1、enemy2)同时遭受attacker时的受伤害情况(enemy2由于级别较低,掉血较多)

    /// <summary>
    /// 模拟两个小怪(enemy1、enemy2)同时遭受attacker时的受伤害情况
    /// enemy2由于级别较低,掉血较多
    /// attacker 可以进行普通攻击和魔法攻击,同时发布两种攻击发起时,遭受者的反应
    /// enemy1、enemy2对遭受两种攻击时的反应进行了订阅
    /// </summary>
    public delegate void reactEventhander();//定义一个委托
    class Attacker
    {
        public event reactEventhander RegularReact;//发布两个事件
        public event reactEventhander MagicReact;

        //定义事件触发的条件
        //攻击者发动普通攻击时,被攻击者的反应
        public void RegularAttack()
        {
            Console.WriteLine("发起了普通攻击!");
            if(RegularReact!=null)//判断事件是否被订阅
            {
                RegularReact();
            }
        }

        public void MagciAttack()
        {
            Console.WriteLine("发起了魔法攻击!");
            if (RegularReact != null)//判断事件是否被订阅
            {
                MagicReact();
            }
        }

    }

    class Enemy1
    {
        public Enemy1(Attacker a)
        {
            //Enemy1对事件进行了订阅,遭受攻击时反应
            a.RegularReact += new reactEventhander(a_RegularAttacek);
            a.MagicReact += new reactEventhander(a_MagciAttacek);
        }
        
        //受到普通攻击时的反应
        public void a_RegularAttacek()
        {
            Console.WriteLine("Enemy1遭受普通攻击,掉血100!");
        }
        //受到魔法攻击时的反应
        public void a_MagciAttacek()
        {
            Console.WriteLine("Enemy1遭受魔法攻击,掉血100!");
        }
    }

    class Enemy2
    {
        public Enemy2(Attacker a)
        {
            //Enemy1对事件进行了订阅,遭受攻击时反应
            a.RegularReact += new reactEventhander(a_RegularAttacek);
            a.MagicReact += new reactEventhander(a_MagciAttacek);
        }

        //受到普通攻击时的反应
        public void a_RegularAttacek()
        {
            Console.WriteLine("Enemy2遭受普通攻击,掉血300!");
        }
        //受到魔法攻击时的反应
        public void a_MagciAttacek()
        {
            Console.WriteLine("Enemy2遭受魔法攻击,掉血300!");
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Attacker att = new Attacker();
            Enemy1 e1 = new Enemy1(att);
            Enemy2 e2 = new Enemy2(att);

            att.RegularAttack();
            att.MagciAttack();
            Console.ReadKey();
        }
    }

仔细会看此例子,剥去所有的乱七八糟的,也不过是attacker的regularattack和magicattack方法调用了enemy1/2的a_RegularAttacek和a_MagciAttacek方法,只不过是通过attacker发布的两个事件进行订阅的。从此小例子上来讲,为了帮助理解,此处完全可以去掉两个event,在两个enemy的a_RegularAttacek和a_MagciAttacek方法中加入委托类型的入口参数。但是事件的这种机制思想确实很重要的,以后会慢慢体会到的。

 

C#事件