之前的博客讲到委托,委托本质上是将方法作为方法的参数传给方法。实际开发中,实现某个功能的的代码通常会封装成一个类,本例中字符串处理封装成MyStringProc类,
代码如下:
 namespace DelegateTest
{
public delegate string MyStringProcDelegate(string str);
class MyStringProc
{
public string ProcString(string str,MyStringProcDelegate strProcDelegate)
{
return strProcDelegate(str);
}
}
}

在调用的时候实例化这个类,再调用对应的方法。如下:

 namespace DelegateTest
{
class Program
{
static void Main(string[] args)
{
MyStringProc msp = new MyStringProc();
string str1=msp.ProcString("I am good.", StringToLower);
string str2 = msp.ProcString("I am good too", StringToUpper);
Console.WriteLine("{0},{1}",str1,str2);
Console.ReadKey();
}
static string StringToLower(string str)
{
return str.ToLower();
}
static string StringToUpper(string str)
{
return str.ToUpper();
}
}
}
输出如下:
 
现在如果要实现某个功能,这个功能包含多种类型但操作参数都相同,只是内部逻辑不同,而且要依次调用其中几个,这时我们可以只定义一个委托变量,将这些操作的方法依次绑定到这个委托变量即可。
下面是处理一个字符串:字符串前后加'[]',前后后加'{}',代码如下:
 class Program
{
static void Main(string[] args)
{
MyStringProc msp = new MyStringProc();
MyStringProcDelegate strProcDelegate;
strProcDelegate = StringProc1;
strProcDelegate += StringProc2;
msp.ProcString("I am a good boy",strProcDelegate);
Console.ReadKey();
} static string StringProc1(string str)
{
str= "["+str+"]";
Console.WriteLine(str);
return str;
}
static string StringProc2(string str)
{
str= "{" + str + "}";
Console.WriteLine(str);
return str;
}
}

输出如下:

以上并没有达到完全封装,本例用到的MyStringProcDelegate类型的委托变量是可以封装在MyStringProc类中,客户端直接调用该类的方法即可,无需再声明委托变量。如下:

 public delegate string MyStringProcDelegate(string str);
class MyStringProc
{
public MyStringProcDelegate strProcDelegate;
public string ProcString(string str)
{
if (strProcDelegate!=null)
str=strProcDelegate(str);
return str;
}
}

调用代码如下:

 class Program
{
static void Main(string[] args)
{
MyStringProc msp = new MyStringProc();
msp.strProcDelegate = StringProc1;
msp.strProcDelegate += StringProc2;
msp.ProcString("I am a good boy");
Console.ReadKey();
}
static string StringProc1(string str)
{
str= "["+str+"]";
Console.WriteLine(str);
return str;
}
static string StringProc2(string str)
{
str= "{" + str + "}";
Console.WriteLine(str);
return str;
}
}

输出如下:

 
事件
上面的改进无需再客户端声明委托变量,直接调用功能类的方法即可,但是委托变量声明成了public类型,意思就是说客户端可以随意操作该委托变量,破环了面向对象中的封装性。
假如我们将委托变量进行封装,类似于对字段的封装成属性,在c#中event就是对委托类型变量的一种封装,加上event关键字实际上是将普通的委托封装成具有Add和Remove方法
的一种特殊的委托,后面我用reflector反编译工具查看。
 
代码修改如下:
 public delegate string MyStringProcDelegate(string str);
class MyStringProc
{
public event MyStringProcDelegate strProcDelegate;
public string ProcString(string str)
{
if (strProcDelegate != null)
str = strProcDelegate(str);
return str;
}
}

调用方法如下:

 class Program
{
static void Main(string[] args)
{
MyStringProc msp = new MyStringProc();
msp.strProcDelegate += StringProc1;
msp.strProcDelegate += StringProc2;
msp.ProcString("I am a good boy");
Console.ReadKey();
}
static string StringProc1(string str)
{
str= "["+str+"]";
Console.WriteLine(str);
return str;
}
static string StringProc2(string str)
{
str= "{" + str + "}";
Console.WriteLine(str);
return str;
}
}

输出如下:

这样做的好处是,限定了委托的使用,可防止已注册该事件的方法被非法调用。注:事件只能用+=或-=。
下面是对定义的strProcDelegate 变量反编译结果,从中可看出我们在类中定义的该委托变量最终会编译成add、remove两个方法,add为对委托注册方法,remove为对委托取消注册方法。
 
而且虽然strProcDelegate 变量声明称public,但最终会编译成private,如下:
 
MyStringProcDelegate委托类型最终编译如下:

c#中的事件的更多相关文章

  1. C++中的事件分发

    本文意在展现一个C++实现的通用事件分发系统,能够灵活的处理各种事件.对于事件处理函数的注册,希望既能注册到普通函数,注册到事件处理类,也能注册到任意类的成员函数.这样在游戏客户端的逻辑处理中,可以非 ...

  2. javascript中的事件冒泡和事件捕获

    1.事件冒泡 IE 的事件流叫做事件冒泡(event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档).以下面的HTML ...

  3. jQuery文本框中的事件应用

    jQuery文本框中的事件应用 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "ht ...

  4. 怎么理解js中的事件委托

    怎么理解js中的事件委托 时间 2015-01-15 00:59:59  SegmentFault 原文  http://segmentfault.com/blog/sunchengli/119000 ...

  5. jQuery中的事件绑定方法

    在jQuery中,事件绑定方法大致有四种:bind(),live(), delegate(),和on(). 那么在工作中应该如何选择呢?首先要了解四种方法的区别和各自的特点. 在了解这些之前,首先要知 ...

  6. 四、jquery中的事件与应用

    当用户浏览页面时,浏览器会对页面代码进行解释或编译--这个过程实质上是通过时间来驱动的,即页面在加载时,执行一个Load事件,在这个事件中实现浏览器编译页面代码的过程.时间无论在页面元素本身还是在元素 ...

  7. ActiveX(二)Js 监听 ActiveX中的事件

    在上一篇随笔:ActiveX(一)第一个简单的Demo 中,已经可以实现 js 单向调用 ActiveX 中的方法,在很多情况下ActiveX中的方法的执行时相对耗时.耗性能的.在这样的情况下.Act ...

  8. jQuery:详解jQuery中的事件(二)

    上一篇讲到jQuery中的事件,深入学习了加载DOM和事件绑定的相关知识,这篇主要深入讨论jQuery事件中的合成事件.事件冒泡和事件移除等内容. 接上篇jQuery:详解jQuery中的事件(一) ...

  9. jQuery:详解jQuery中的事件(一)

    之前用过一些jQuery的动画和特效,但是用到的部分也不超过10%的样子,感觉好浪费啊——当然浪费的不是jQuery,而是Web资源.后来就想深入研究下jQuery的内部机理,读过两遍jQuery源代 ...

  10. DOM中的事件对象

    三.事件对象事件对象event1.DOM中的事件对象(1).type:获取事件类型(2).target:事件目标(3).stopPropagation() 阻止事件冒泡(4).preventDefau ...

随机推荐

  1. NGUI Draw Calls优化(思路)

    用NGUI做界面的时候发现不注意GameObject(或者说Widget)的depth的话,单独运行界面时,Draw Calls挺高的: 网上搜了一下,大把的博客说的都是类似以下的原则: (PS:以下 ...

  2. ascii文件转为utf-8格式

    import codecs import os #格式转换 fhanzi1 = codecs.open(os.path.join(outputpath,"hanzi1.txt"), ...

  3. Java 读取Properties配置文件

    1.img_url.properties imgurl=http://10.1.19.65:8090 2.Test.java InputStream inputStream = this.getCla ...

  4. linq 多条件查询

    Linq 进行多条件查询的时候使用PredicateBuilder帮助类可以很好的解决. 类的源码: public static class PredicateBuilder { /// <su ...

  5. PRISM ‘VS100COMNTOOLS’ not set. Cannot set the build environment

    prism 注册dll,出现以上错误 在系统环境变量,增加 VS100COMNTOOLS 设置路径C:\Program Files (x86)\Microsoft Visual Studio 11.0 ...

  6. 何时使用Swift Structs和Classes

    Swift 圈中有一个被反复讨论的话题是:何时使用struct,何时使用class.我觉得今天我也要给出我的个人观点. 值 VS 引用 答案真的很简单了:当你需要用值语义的时候使用class,需要用引 ...

  7. 2600: [Ioi2011]ricehubh

    Description 乡间有一条笔直而长的路称为"米道".沿着这条米道上 R 块稻田,每块稻田的坐标均为一个 1 到 L 之间(含 1 和 L)的整数.这些稻田按照坐标以不减的顺 ...

  8. 怎么把U盘启动改为硬盘启动(适用于U盘安装系统时)

    两种方法: 一:安装时: 在自定义创建分区后,如图: 选择系统的启动程序安装的位置,在change  device 里设置第一启动装置,和第二启动装置! 二:安装后: 开机未进入系统按F2,进入BIO ...

  9. WebService 基本操作

    1.新建asp.net web 应用程序 2.添加web 服务webservice.asmx public string HelloWorld(int a) { if (a==1) { return ...

  10. 【洛谷P3258】松鼠的新家

    很好的一道题 LCA+树上前缀和 sum数组是前缀和数组, 分类讨论一下, 1.访问到一个点p1,若下一个点p2需要往儿子下面找的话,那么lca就是这个点p1,则sum[p1]--; sum[p2]+ ...