C# 事件与委托

1. 最近重温c# 基础, 看到微软MVP刘铁锰老师的视频,其中委托和事件,讲的让我受益匪浅,所以记录下学习心得。

 

2. 委托(delegate):

2.1 在c# 中,委托是一种类(class), 由于普通类(class)是一种数据类型,所以委托(delegate) 也是一种数据类型,它与类同级。

只是,由于它比较特殊,声明的方式与一般类不同,根据刘铁锰老师视频,这样子声明方式主要是为了照顾可读性和c/c++ 传统。

2.2  声明委托的位置 (避免声明嵌套类型)

在我以前,使用Wimform 编程时,一般在多线程访问UI线程时,主要使用委托,但是由于对委托理解不够深入(delegate与class 同级),一般定义委托的位置都是类里面。形成嵌套类型。

根据教程中提到,委托也是一种类,所以,声明委托时,尽量与类的声明同级。

 2.3 在c#中的委托Action 和 Func<T> 泛型。

2.4 委托两种调用方式, 如: 

public delegate void Action(int x, int y);

Action action = new Action();

 

2.4.1  同步调用:action.Invoke(1, 2);    或者  action(1, 2);  

2.4.2  异步调用:  action.BeginInvoke(1, 2);

 

3. 事件

3.1. 初步了解事件: 

(1)定义: 单词Event , 中文译为“事件”,能够发生的事情。

(2)角色: 是使用的对象,或者类,具备通知能力成员。 棣属于类或对象,不能脱离类或对象。

(中文翻译) 事件(Event) 是一种能使对象或者类能够提供通知的成员

(英文原版) An event is a member that enables an object or class to provide notifications.

(3) 使用: 用户对象或者类间的动作协调与信息传递 (即消息推送)。

原理: 事件模型 (Event  model) 

其中, a. 事件订阅者,事件消息的接受者, 事件的响应者,事件的处理者,被事件所通知的对象, 这5个都是指同一个东西。

b. 事件消息, 事件信息,事件数据,事件参数, 这4个都是指同一个东西。

 

3.2 事件的应用

(1) 事件模型的5个组成部分:

a. 事件拥有者(event source, 类或对象)

b. 事件成员( event, 成员)

c. 事件响应者(event subscriber, 对象)

d. 事件处理器(event handler, 成员)  ----- 本质上是一个回调的成员方法

e. 事件订阅 --- 把事件处理器 与事件关联一起,本质是一种以委托为基础的“约定”。

注意:

a1. 事件处理器是方法成员,

a2. 挂接事件处理器的时候,可以使用委托实例(委托本质上一种类) ,也可以直接使用方法名,这是个语法糖。

a3. 事件处理器对事件的订阅不是随意的,编译器会匹配与是否由声明事件时所使用的委托类型(再次说明委托是一个类)来检测。

a4. 事件可以同步调用(Event.Invoke),或者异步调用 (Event.BeginInvoke).

有这几种 情况,

 

4. 自定义事件

4.1 定义事件信息类型,按照.Net 规定,事件信息的命名,以事件 + EventArgs 后缀,并继承EventArgs
 

public class OrderEventArgs:EventArgs
{
    public String DishName { get; set; }

    public String Size { get; set; }
}

 

4.2 定义事件拥有者和委托:

根据.Net 的规定,如果委托,是为了声明的某个事件而准备的,需要在委托后面增加EventHandler 后缀。

     /// <summary>
    /// 使用EventHandler 用意:
    /// 1. 看到EventHandler 后缀, 这个委托是用来声明事件
    /// 2. 表明这个委托是用来声明事件,约束事件处理器
    /// 3. 委托示例,存储事件处理器
    /// </summary>
    /// <param name="customer"></param>
    /// <param name="args"></param>
    public delegate void OrderEventHandler(Customer customer, OrderEventArgs args);

     /// <summary>
    /// 事件拥有者
    /// </summary>
    public class Customer
    {
    }

    /// 使用EventHandler 用意:
    /// 1. 看到EventHandler 后缀, 这个委托是用来声明事件
    /// 2. 表明这个委托是用来声明事件,约束事件处理器
    /// 3. 委托示例,存储事件处理器

  委托也是一种类,所以,声明委托时,尽量与类的声明同级,避免嵌套。

4.3 定义事件

由于在上面提到,事件是使用的对象,或者类,具备通知能力成员。 棣属于类或对象,不能脱离类或对象。

因此,需要把事件定义到事件拥有者上面,并且使用上面定义的委托声明来约束事件。

/// <summary>
    /// 使用EventHandler 用意:
    /// 1. 看到EventHandler 后缀, 这个委托是用来声明事件
    /// 2. 表明这个委托是用来声明事件,约束事件处理器
    /// 3. 委托示例,存储事件处理器
    /// </summary>
    /// <param name="customer"></param>
    /// <param name="args"></param>
    public delegate void OrderEventHandler(Customer customer, OrderEventArgs args);

    /// <summary>
    /// 事件拥有者
    /// </summary>
    public class Customer
    {
        //创建存储事件处理的委托
        private OrderEventHandler orderEventHandler;

        //创建委托约束的事件  -- 事件最基本的创建放方式, 
        public event OrderEventHandler Order
        {
            add        //添加器
            {
                this.orderEventHandler += value;
            }

            remove    //移除器
            {
                this.orderEventHandler -= value;
            }
        }
    }

4.4 定义事件响应者和事件处理器

 /// <summary>
    /// 事件响应者
    /// </summary>
    public class Waiter
    {
        /// <summary>
        /// 事件处理器
        /// </summary>
        /// <param name="customer"></param>
        /// <param name="args"></param>
        public void EventAction(Customer customer, OrderEventArgs e)
        {
            Console.WriteLine("I will serve you the dish - {0}", e.DishName);

            double price = 10;

            switch (e.Size)
            {
                case "small":
                    customer.Bill = price * 0.5;
                    break;

                case "large":
                    customer.Bill = price * 1.5;
                    break;
            }
        }   
    }

上面也提到,事件处理器(event handler, 成员)  ----- 本质上是一个回调的成员方法

4.5 在事件拥有者中,增加触发方法

 /// <summary>
    /// 使用EventHandler 用意:
    /// 1. 看到EventHandler 后缀, 这个委托是用来声明事件
    /// 2. 表明这个委托是用来声明事件,约束事件处理器
    /// 3. 委托示例,存储事件处理器
    /// </summary>
    /// <param name="customer"></param>
    /// <param name="args"></param>
    public delegate void OrderEventHandler(Customer customer, OrderEventArgs args);

    /// <summary>
    /// 事件拥有者
    /// </summary>
    public class Customer
    {
        //创建存储事件处理的委托,但是没有分配
        private OrderEventHandler orderEventHandler;

        //创建委托约束的事件  -- 事件最基本的创建放方式, 
        public event OrderEventHandler Order
        {
            add
            {
                this.orderEventHandler += value;
            }

            remove
            {
                this.orderEventHandler -= value;
            }
        }

        public double Bill { get; set; }

        public void PlayTheBill()
        {
            Console.WriteLine("I will pay ¥{0}", this.Bill);
        }

        public void Walkln()
        {
            Console.WriteLine("Walk into the restaurant");
        }

        public void SitDown()
        {
            Console.WriteLine("Sit down");
        }

        //事件触发,都是由事件拥有者,内部一些逻辑方法触发, 然后调用事件处理器
        public void Think()
        {
            for (int ik = 0; ik < 5; ik++)
            {
                Console.WriteLine("Let me think 。。。。。");
                Thread.Sleep(1000);
            }

            //触发事件处理器,需要判断是否增注册了事件处理
            if (this.orderEventHandler != null)
            {
                OrderEventArgs e = new OrderEventArgs();

                e.DishName = "KongPao Chicken";
                e.Size = "large";

                this.orderEventHandler.Invoke(this, e);

                //函数指针用法
                //this.orderEventHandler(this, e);
            }
        }

        public void Action()
        {
            Console.WriteLine("Please input enter: ");
            Console.ReadLine();

            this.Walkln();
            this.SitDown();
            this.Think();
        }

    }

 

5. 关于事件声明

5.1 事件的声明:

a. 完整声明, 上面就是完整声明,

(1) 在事件拥有者类中先定义委托, 
   private OrderEventHandler orderEventHandler;

 (2)使用委托约束定义事件

   //创建委托约束的事件  -- 事件最基本的创建放方式, 
        public event OrderEventHandler Order
        {
            add
            {
                this.orderEventHandler += value;
            }

            remove
            {
                this.orderEventHandler -= value;
            }
        }

b. 简略声明(字段式声明,field-like)

public event OrderEventHandler Order;

//访问权限, event 创建事件, OrderEventHandler (哪种委托类型,作为事件的约束), Order 事件名字

 

5.2 有了委托字段/属性, 为什么还要事件?

为了程序的逻辑更加有道理,更加安全。

所以,事件的本质,是委托字段的一个包装器。

a. 这个包装器对委托字段访问器限制作用。

b. 封装的一个重要功能就是隐藏。

c. 事件对外界隐藏了委托实例的大部分功能,仅暴露了增加/移除事件处理器功能。

 

5.3 根据.Net 规定,最终修改如下:

 /// <summary>
    /// 使用EventHandler 用意:
    /// 1. 看到EventHandler 后缀, 这个委托是用来声明事件
    /// 2. 表明这个委托是用来声明事件,约束事件处理器
    /// 3. 委托示例,存储事件处理器
    /// </summary>
    /// <param name="customer"></param>
    /// <param name="args"></param>
    //public delegate void OrderEventHandler(Customer customer, OrderEventArgs args);
    public delegate void OrderEventHandler(Object sender, EventArgs e);
    
    /// <summary>
    /// 事件拥有者
    /// </summary>
    public class Customer
    {
        /*
        //创建存储事件处理的委托
        private OrderEventHandler orderEventHandler;

        //创建委托约束的事件  -- 事件最基本的创建放方式, 
        public event OrderEventHandler Order
        {
            add
            {
                this.orderEventHandler += value;
            }

            remove
            {
                this.orderEventHandler -= value;
            }
        }*/


        //使用指定的委托类型,定义事件名字
        public event OrderEventHandler Order;

        public double Bill { get; set; }

        public void PlayTheBill()
        {
            Console.WriteLine("I will pay ¥{0}", this.Bill);
        }

        public void Walkln()
        {
            Console.WriteLine("Walk into the restaurant");
        }

        public void SitDown()
        {
            Console.WriteLine("Sit down");
        }

        //事件触发,都是由事件拥有者,内部一些逻辑方法触发, 然后调用事件处理器
        public void Think()
        {
            for (int ik = 0; ik < 5; ik++)
            {
                Console.WriteLine("Let me think 。。。。。");
                Thread.Sleep(1000);
            }

            //触发事件处理器
            //if (this.orderEventHandler != null)
            if(this.Order != null)
            {
                OrderEventArgs e = new OrderEventArgs();

                e.DishName = "KongPao Chicken";
                e.Size = "large";

                //this.orderEventHandler.Invoke(this, e);

                //函数指针用法
                //this.orderEventHandler(this, e);

                //直接调用
                this.Order.Invoke(this, e);
            }
        }

        public void Action()
        {
            Console.WriteLine("Please input enter: ");
            Console.ReadLine();

            this.Walkln();
            this.SitDown();
            this.Think();
        }

    }
    /// <summary>
    /// 事件响应者
    /// </summary>
    public class Waiter
    {
        /// <summary>
        /// 事件处理器
        /// </summary>
        /// <param name="customer"></param>
        /// <param name="args"></param>
        //public void EventAction(Customer customer, OrderEventArgs e)
        public void EventAction(Object sender, EventArgs e)
        {
            Customer customer = sender as Customer;
            OrderEventArgs e1 = e as OrderEventArgs;

            Console.WriteLine("I will serve you the dish - {0}", e1.DishName);

            double price = 10;

            switch (e1.Size)
            {
                case "small":
                    customer.Bill = price * 0.5;
                    break;

                case "large":
                    customer.Bill = price * 1.5;
                    break;
            }
        }   
    }

执行事件

  static void Main(string[] args)
        {
            //创建事件拥有者
            Customer customer = new Customer();

            //创建事件处理者
            Waiter waiter = new Waiter();

            //注册事件处理器
            customer.Order += waiter.EventAction;

            //触发事件
            customer.Action();

            customer.PlayTheBill();
        }

 

综上,委托与事件原来是这层关系。通过刘铁锰老师讲解,有终于理解了,事件是什么,委托是什么。

 

 

参考《刘铁锰老师C# 基础视频讲义》

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值