前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C#委托五(自定义事件)

C#委托五(自定义事件)

作者头像
aehyok
发布2018-09-11 12:10:23
1.2K0
发布2018-09-11 12:10:23
举报
文章被收录于专栏:技术博客

事件:

"在发生其他类或对象关注的事情时,类或对象可以通过事件通知他们。发送(或引发)事件的类称为"发行者",接受(或处理)事件的类称为"订户"。"

上面这句话描述了事件的最本质功能,用于底层通知上层。正常的架构设计都是分层结构,而分层结构有一点很重要的就是底层对于上层的无知,当初这样设计是为了解耦,为了更好的面向对象,但是带来的问题是如何解决自下而上的信息流。因为自上而下的调用,我们通过接口就可以搞定一切了,上层可以看到下层提供的服务接口,那么正常的调用可以保证一路向下,底层调用中层提供的服务接口,中层的服务接口的实现中调用了底层的服务接口,这样感觉很是完美的设计模式。每一层都不再依赖彼此,隐藏了实现细节。但是现在遇到一个最简单的问题:如果需要底层来触发上层的行为,如何实现。很多程序员告诉我这个简单,轮询啊,底层不断轮询这一个事情的发生状况,如果发生了则启动一个线程专门去处理这个事情。这种解决方案只需要在底层多开出一个服务接口,该服务接口就是表示目前发生了什么事情,然后上层定时查看该接口,如果发生则采取相应操作。当然该种解决方案也是一种解决途径,但是估计你也觉得不好,第一无法实时,因为轮询,那么必定存在一个时差问题,也就是常说的响应时间问题。还有就是单独的轮询线程需要空间与时间的消耗。最让人郁闷还在于这个对于时空的消耗竟然与响应时间是反相关的,总之你想响应时间短,那么就意味着你不得不浪费大量时空,反之亦然。当然此种方法还要解决多线程冲突的问题,涉及到多线程冲突,锁解锁的问题,那么我觉得就不怕你的逻辑能力有多强,耐心有多大,随着项目规模的变大,线程的变多,你大脑崩溃那是早晚的事情。   此处我们引入事件模式。

先来看看事件的特征: ?发行者确定何时引发事件,订户确定执行何种操作来响应该事件 ?一个事件可以有多个订户。一个订户可处理来自多个发行者的多个事件 ?没有订户的事件永远不会被调用 ?事件通常用于通知用户操作 ?如果一个事件有多个订户,当引发该事件时,会同步调用多个事件处理程序 ?支持异步调用 ?可以利用事件同步线程 ?在 .NET Framework 类库中,事件是基于 EventHandler 委托和 EventArgs 基类的

C#类库中自带了一大堆事件,尤其那些控件。而对于我说到的这个底层触发上层的问题,那么绝大多数是需要自定义事件的。(库中自带事件的使用我就不讲了,如果这个你不会的话,未免对不起观众了。)所以下面就开始着重讲讲自定义事件的问题:

事件是类和对象向外界发出的消息,事件的执行是通过事件委托的方式,调用我们所准备好的处理方法。要响应某些事件并针对某些事件执行我们指定的方法,需要做到以下几步:

  • 声明委托、事件
代码语言:javascript
复制
        ///定义一个委托
        public delegate void TestEventHandler(object sender, TestEventArgs e);
        ///用event关键字声明事件对象
        public event TestEventHandler TestEvent;
  • 添加事件的触发方法,也就是通知接受者方法
代码语言:javascript
复制
        //事件触发的方法
        protected  void OnTestEvent(TestEventArgs e)
        {
            if (TestEvent != null)
            {
                TestEvent(this, e);
            }
        }
  • 添加事件引发方法
代码语言:javascript
复制
        //引发事件的方法
        public void RaiseEvent(char keyToRaiseEvent)
        {
            TestEventArgs e = new TestEventArgs(keyToRaiseEvent);
            OnTestEvent(e);
        }
  • 接受者处本地化响应方法
代码语言:javascript
复制
        //定义本地处理事件的方法,他与声明事件的delegate具有相同的参数和返回值类型 
        public void KeyPressed(object sender, TestEventSource.TestEventArgs e)
        {
            Console.WriteLine("发送者:{0},所按得健为:{1}", sender, e.KeyToRaiseEvent);
        }
  • 接受者订阅事件
代码语言:javascript
复制
        //订阅事件 
        public void Subscribe(TestEventSource evenSource)
        {
            evenSource.TestEvent += new TestEventSource.TestEventHandler(KeyPressed);
        }

        //取消订阅事件 
        public void UnSubscribe(TestEventSource evenSource)
        {
            evenSource.TestEvent -= new TestEventSource.TestEventHandler(KeyPressed);
        } 

  最终全部代码如下:

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    /// <summary>
    /// 发布事件类
    /// </summary>
    public class TestEventSource
    {
        /// <summary>
        /// 定义事件参数类
        /// </summary>
        public class TestEventArgs : EventArgs
        {
            public readonly char KeyToRaiseEvent;
            public TestEventArgs(char keyToRaiseEvent)
            {
                KeyToRaiseEvent = keyToRaiseEvent;
            }
        }

        ///定义一个委托
        public delegate void TestEventHandler(object sender, TestEventArgs e);
        ///用event关键字声明事件对象
        public event TestEventHandler TestEvent;

        //事件触发的方法
        protected  void OnTestEvent(TestEventArgs e)
        {
            if (TestEvent != null)
            {
                TestEvent(this, e);
            }
        }

        //引发事件的方法
        public void RaiseEvent(char keyToRaiseEvent)
        {
            TestEventArgs e = new TestEventArgs(keyToRaiseEvent);
            OnTestEvent(e);
        }
    }

    //监听事件类
    public class TestEventListener 
    {
        //定义本地处理事件的方法,他与声明事件的delegate具有相同的参数和返回值类型 
        public void KeyPressed(object sender, TestEventSource.TestEventArgs e)
        {
            Console.WriteLine("发送者:{0},所按得健为:{1}", sender, e.KeyToRaiseEvent);
        }

        //订阅事件 
        public void Subscribe(TestEventSource evenSource)
        {
            evenSource.TestEvent += new TestEventSource.TestEventHandler(KeyPressed);
        }

        //取消订阅事件 
        public void UnSubscribe(TestEventSource evenSource)
        {
            evenSource.TestEvent -= new TestEventSource.TestEventHandler(KeyPressed);
        } 

    }

    class Program
    {
        static void Main(string[] args)
        {
            ///创建事件源对象
            TestEventSource es = new TestEventSource();

            ///创建监听对象
            TestEventListener el = new TestEventListener();

            ///订阅事件
            Console.WriteLine("订阅事件\t");
            el.Subscribe(es);

            ///引发事件
            Console.WriteLine("输入一个字符,再按enter键");
            string str = Console.ReadLine();
            es.RaiseEvent(str.ToCharArray()[0]);

            //取消订阅事件 
            Console.WriteLine("\n取消订阅事件\n");
            el.UnSubscribe(es);


            //引发事件 
            Console.WriteLine("输入一个字符,再按enter健");
            str = Console.ReadLine();
            es.RaiseEvent(str.ToCharArray()[0]);
            Console.ReadLine();

        }
    }
}

赋值粘贴即可以执行,且看下面截图执行效果:

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2013-02-22 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档