C# event 事件-2

  本次是对第一篇事件随笔的补充笔记,涉及题目依然使用上一篇的习题。上一篇地址:https://www.cnblogs.com/FavoriteMango/p/11685702.html

  1.事件的定义

  事件的定位可以参考属性,C#中,属性是对字段的封装,相对而言,基于委托来声明的事件也是对委托的封装,但是属性≠字段,同样事件≠委托。至于为何封装,可另行查阅文档。

  2.事件的简要声明和详细声明

  通常的学习案例中大部分对事件的使用都是通过简要声明(语法糖)的方式使用的,包括上一篇随笔中我初学事件时的例子,但这次有接触到事件声明的详细流程。

  事件的简要声明中省略了对委托字段的声明步骤,由于Action和Fun这两个委托类,你甚至可以完全不声明委托类型,并且由于语法糖,你可能会把委托和事件完全混淆,这是错误的。

  事件的详细声明需要有对委托类型的定义,事件参数的定义,委托字段的定义,还有事件本身的定义,对事件的定义中还有add和remove关键字以及相关逻辑的处理(add和remove可以用属性的get、set的定义来参考),强烈建议通过详细的声明流程来理解事件。

  3.定义事件时需要的一些参数

  虽然没有硬性规定事件必须要有哪些参数,但所有事件基于情理最好有两个参数,第一个是事件的发起者,第二个是事件所包含的相关信息。参考Winform,所有的事件都有sender和e两个参数,他们分别对应发起者和信息。

  在这里C#将sender定义为Object,也给出了基本的信息类(EventArgs类),而自定义的信息类都要继承EventArgs类,并且在定义类的时候类名都要加EventArgs为后缀(例如后面的AnimalEventArgs),这是一种命名规范。

  4.其他一些要注意的地方

  声明委托类型时,要注意同为数据类型的委托是和类(class)平级的存在,它应当(但不绝对)声明在和类平级的命名空间里。

  简要声明是一种语法糖,它简化了了事件的使用流程,但是也容易混淆概念,在下面的代码中请重点注意在事件的发起者中对于事件的定义和事件的触发两处的代码。

  5.习题部分

  回到习题,依然是开枪的事件,首先是事件的相关参数的定义,包括委托类型的定义,事件信息类的定义:

    //声明委托类型 
    //Parson : 事件发起者的类
    public delegate void FireEventHandler(Parson parson, FireEventArgs e);

    /// <summary>
    /// 事件参数中的信息类
    /// </summary>
    public class FireEventArgs : EventArgs
    {
        public Animal Animal { get; set; }
    }

  然后是事件的发起者和订阅者

/// <summary>
    /// 事件的发起者
    /// </summary>
    public class Parson
    {
        //委托类型的字段
        private FireEventHandler fireEventHandler;
        
        //封装委托类型的事件
        public event FireEventHandler Fire
        {
            add
            {
                //添加事件处理器 
                //value:在订阅事件时添加的事件处理器
                this.fireEventHandler += value;
            }
            remove
            {
                //移除事件处理器
                this.fireEventHandler -= value;
            }
        }
        
        public string Name { get; set; }

        public void OnFire(FireEventArgs e)
        {
            Console.WriteLine("{0}正在开枪。", Name);

            if (fireEventHandler != null)
            {
                //触发事件
                fireEventHandler.Invoke(this, e);
            }
        }
    }

    /// <summary>
    /// 事件的订阅者
    /// </summary>
    public class Animal
    {
        public string Name { get; set; }

        internal void Action(Parson sender, FireEventArgs e)
        {
            Console.WriteLine("由于" + sender.Name + "开枪," + e.Animal.Name + "受到了惊吓。"); if (e.Animal.Name == "") { Console.WriteLine(e.Animal.Name + "飞了"); } } }

  最后是订阅事件

    class Program
    {
        static void Main(string[] args)
        {
            //人开枪,鸟飞了
            //事件拥有者:人
            //事件本身:开枪
            //事件响应者:鸟
            //事件处理:飞了
            //订阅关系:鸟 → 开枪
            //事件的完整声明

            Parson parson = new Parson { Name = "Your name" };

            Animal animal = new Animal { Name = "Animal name" };

            parson.Fire += animal.Action;

            parson.OnFire(new FireEventArgs { Animal = animal });
        }
    }

  把Animal的name属性赋值为“鸟”

    class Program
    {
        static void Main(string[] args)
        {
            //人开枪,鸟飞了
            //事件拥有者:人
            //事件本身:开枪
            //事件响应者:鸟
            //事件处理:飞了
            //订阅关系:鸟 → 开枪
            //事件的完整声明

            Parson parson = new Parson { Name = "Your Name" };

            Anime anime = new Anime { Name = "" };

            parson.Fire += anime.Action;

            parson.OnFire(new FireEventArgs { Anime = anime });
        }
    }

  运行可得结果:

猜你喜欢

转载自www.cnblogs.com/FavoriteMango/p/11731485.html