去年学习C#的时候按照进度把C#的委托和事件“认真”的学习了一下,自己知道委托和事件的重要性,所以也努力的学习,可说实也没怎么学懂。碰巧这段时间在做一个解析GPS数据的小项目,因为其中有需要条件自动判断并处理的模块,因此首先想到的就是委托和事件。借此机会重新学习和复习了一下,收获颇丰。

  什么是委托?根据我的理解委托就是把一件可能发生的事情,当满条件达到时委托别人帮忙处理。根据从书上看到的委托应该是有C++的函数指针发展而来的,只不过C#中一般不用指针。在这里举一个小例子,输入一个字符串当它的长度满足指定长度时输出,达到指定长度就是触发了事件。

class AutoDisposeStr
    {

public AutoDisposeStr(int length)
        {
            LimitLength = length;
        }
        public delegate void DisplaysrtHandler();
        public  DisplaysrtHandler MeetLength;

public void OnReadAndDisplay()
        {
            Console.WriteLine(str);
        }

public DisplaysrtHandler MeetLength
        {
           get { return _MeetLength; }
           set { _MeetLength = value; }
        }
        public int LimitLength
        {
            get { return _LimitLength; }
            set { _LimitLength = value; }
        }

public string str
        {
            get { return _str; }
            set
            {
                if (value.Length >= LimitLength)
                {
                    _str = value;
                    MeetLength();
                }
            }
        }

private int _LimitLength;
        private string _str;
        private DisplaysrtHandler _MeetLength;
    }
}

  首先构建了一AutoDisposeStr类有三个字段_LimitLength表示处理字符串的门限值对应的属性为LimitLength,_Str将要处理的字符串对应属性为Str,_MeetLength为委托类型的字段对应属性为MeetLength用来注册监听者。需要注意的是委托类型参数列表和你处理函数的参数列表需要对应,在这里就是 public delegate void DisplaysrtHandler()和public void OnReadAndDisplay()。因为要实时监听字符串长度是否达到门限值,所以要在字符串属性赋值时进行处理。每输入一个字符串,判断长度是否达到门限值,如果达到则调用监听函数处理:

public string str
        {
            get { return _str; }
            set
            {
                if (value.Length >= LimitLength)
                {
                    _str = value;
                    MeetLength();//调用监听函数处理
                }
            }

在这里其实就是把处理的方法委托给了public void OnReadAndDisplay()函数。最后只需要在Main()函数中实例化并注册监听函数即可。委托的用法就这么简单,不过有几点组要注意:

  一:如果当前没有订阅者也就是MeetLength为空执行 MeetLength()会引发异常NullReferenceException,因此为了解决这个问题在触发事件之前检查空值。

DisplaysrtHandler local=MeetLength;

if(local!=null)

{

  local();

}

这里定义了一个局部变量来检查是否为空是为了防止来自不同线程订阅者被移除可能造成NullReferenceException异常,因为MeetLength-=<listener>,会将一个全新的委托指派给MeetLength,这不会对原先local委托有任何影响。

    二,委托链会按注册的顺序调用,但是如果一旦前面的委托发生异常,后面的委托将得不到执行。因此最保险的方法应该用foreach(DisplaysrtHandler myhander in local.GetInvocationList){}同时加上异常处理。

委托就说这么多吧,说的不对的地方欢迎指正共同学习。

接下来说说事件,我感觉事件就是在委托的基础上增加了一些编程的规范。对于委托你可以在任何包容类之外调用委托,这就会造成对包容类内委托结果的影响。不满足封装性要求,其次事件中当注册事件和移除事件时如果不幸将“-=”或“+=”写成了“=”在委托中没有语法错误而是造成了委托连被无意赋值号覆盖掉了,而在事件中这样的大意是不能编译通过的。防止了这种错误的可能性,还有事件中对事件处理函数参数有规范要求,这里就不多讲了。贴上事件的代码以做对比:

class AutoDisposeStr
    {

public class AutoDisposeStrArgs : System.EventArgs
        { }
        public AutoDisposeStr(int length)
        {
            LimitLength = length;
        }
        public delegate void DisplaysrtHandler(object sender, AutoDisposeStrArgs newAutoDisposeStr);
        public event DisplaysrtHandler MeetLength;

public void OnReadAndDisplay(object sender, AutoDisposeStrArgs newAutoDisposeStr)
        {
            Console.WriteLine(str);
        }

//public DisplaysrtHandler MeetLength
        //{
        //    get { return _MeetLength; }
        //    set { _MeetLength = value; }
        //}
        public int LimitLength
        {
            get { return _LimitLength; }
            set { _LimitLength = value; }
        }

public string str
        {
            get { return _str; }
            set
            {
                if (value.Length >= LimitLength)
                {
                    _str = value;
                    MeetLength(this,null);
                }
            }
        }

private int _LimitLength;
        private string _str;
        //private DisplaysrtHandler _MeetLength;
    }

主函数:

class Program
    {
        static void Main(string[] args)
        {
            AutoDisposeStr ads= new AutoDisposeStr(5);
            ads.MeetLength += ads.OnReadAndDisplay;
            for (int i = 0; i < 10; i++)
            {
                ads.str = Console.ReadLine();
            }
        }

本人也是初学者,有说的不对不妥的地方欢迎指正,共同学习,共同进步。

重读C#委托、事件有感的更多相关文章

  1. C# ~ 从 委托事件 到 观察者模式 - Observer

    委托和事件的部分基础知识可参见 C#/.NET 基础学习 之 [委托-事件] 部分: 参考 [1]. 初识事件 到 自定义事件: [2]. 从类型不安全的委托 到 类型安全的事件: [3]. 函数指针 ...

  2. C#委托,事件理解入门 (译稿)

    原文地址:http://www.codeproject.com/Articles/4773/Events-and-Delegates-Simplified 引用翻译地址:http://www.cnbl ...

  3. 关于ios使用jquery的on,委托事件失效

    $('.parents').on("click",'.child',function(){}); 类似上面这种,在ios上点击"child"元素不会起作用,解决 ...

  4. Observer设计模式中-委托事件-应用在消息在窗体上显示

    Observer设计模式:监视者模式.在类中的方法中处理的结果或者消息通过事件委托 的方式发送给主窗体. 因为在其它类中直接访问主窗体类,显示内容是不能直接调用控件赋值的,当然也有别的类似查阅控件名, ...

  5. Asp.net用户控件和委托事件

    在Asp.net系统制作过程中,门户类型的网站,我们可以用DIV+CSS+JS+Ajax全部搞定,但是一旦遇到界面元素比较复杂的时候,还是UserControl比较方便一些,各种封装,各种处理,然后拖 ...

  6. jQuery里面的普通绑定事件和on委托事件

    以click事件为例: 普通绑定事件:$('.btn1').click(function(){}绑定 on绑定事件:$(document).on('click','.btn2',function(){ ...

  7. c#基础学习笔记-----------委托事件

    这里有一个比较简单的委托实例应用(跨窗体操作控件) http://blog.csdn.net/bdstjk/article/details/7004035 还有一个比较详细的介绍并深入理解委托事件的讲 ...

  8. c#委托事件入门--第二讲:事件入门

    上文 c#委托事件入门--第一讲:委托入门 中和大家介绍了委托,学习委托必不可少的就要说下事件.以下思明仍然从事件是什么.为什么用事件.怎么实现事件和总结介绍一下事件 1.事件是什么:. 1.1 NE ...

  9. Unity C#笔记 委托&事件

    C#的委托与事件搭配,即是观察者模式的一种实现. 因为观察者模式的原理很易懂,不作多讲,本文纯粹用于记录语法. delegate(委托) //声明没有参数,没有返回值的委托类型XXXX public ...

  10. JavaScript中事件委托(事件代理)详解

    在JavaScript的事件中,存在事件委托(事件代理),那么什么是事件委托呢? 事件委托在生活中的例子: 有三个同事预计会在周一收到快递.为签收快递,有两种办法:一是三个人在公司门口等快递:二是委托 ...

随机推荐

  1. 构建第一个maven工程

    一.maven介绍 Maven 是一个强大的项目管理和构建自动化工具,它通过抽象的项目对象模型和构建生命周期模型来对项目及其构建过程进行管理,Maven 最大化的消除了构建的重复,提升了构建的效率与标 ...

  2. K米测试

    K米评测 ------K米IOS4.3.0体验之旅 第一部分 :调研,评测 第一次上手体验:  像大多数同学一样,这也是我第一次使用k米这一类型的ktv点歌软件.我算是比较经常接触唱k的人,身边的朋友 ...

  3. BZOJ树链剖分题目汇总

    1036,2157,2243,4034,4196;2325,2908,3083,3159,3531,3626,3999;可以不树剖:1146;2819,2843,4448,4530.

  4. 【原】React中,map出来的元素添加事件无法使用

    在使用react中,经常用到react的map函数,用法和jquery里中的map一样,但是,如果你在每个map出来的元素中添加,你会发觉添加的事件无法关联, 比如,我们很多的评论,我需要在每个评论下 ...

  5. 网摘 窗体的旋转效果 wpf

    <Window x:Class="simplewpf.chuantixx" Name="DW1"         xmlns="http://s ...

  6. DataReader和DataSet的异同

    DataReader:使用时始终占用SqlConnection,在线操作数据库:每次只在内存中加载一条数据,所以占用的内存是很小的:是只进的. 只读的. DataSet:则是将数据一次性加载在内存中. ...

  7. JQuery------获取<input type="file">中的文件内容

    html <div class="File">添加附件</div><input id="upfile" name="up ...

  8. centos设置编码

    CentOS6.5解决中文乱码与设置字符集 Windows的默认编码为GBK,Linux的默认编码为UTF-8.在Windows下编辑的中文,在Linux下显示为乱码.为了解决此问题,修改Linux的 ...

  9. 改造rm命令为mv

    :刚在群里面看到小伙伴误操作把服务器上重要的文件给删掉了,于是google了下,找到一篇文章把rm命令改造成mv命令,源博客如下:http://blog.csdn.net/dataspark/arti ...

  10. 如何在ubuntu中启用SSH服务

    如何在ubuntu14.04 中启用SSH服务 开篇科普:  SSH 为 Secure Shell 的缩写,由 IETF 的网络工作小组(Network Working Group)所制定:SSH 为 ...