之前的博客讲到委托,委托本质上是将方法作为方法的参数传给方法。实际开发中,实现某个功能的的代码通常会封装成一个类,本例中字符串处理封装成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. 关于git-Git 分支管理和冲突解决

    创建分支 git branch 没有参数,显示本地版本库中所有的本地分支名称. 当前检出分支的前面会有星号. git branch newname 在当前检出分支上新建分支,名叫newname. gi ...

  2. 单片机TM4C123学习(九):PWM

    1.头文件与变量定义 #include "tiva_pwm.h" // PWM 2.初始化 // PWM 初始化,频率为1000,占空比为0 M1PWM7_init(, ); // ...

  3. 多重背包问题:POJ2392

    这是一道完全背包问题,只不过增加了限制条件. 在更新最大值的时候,我注释掉了错误的方式,却不明白为什么是错误的,如果有人看到这篇博客,并且知道为什么那样更新是错误的,请指教,谢谢. 上代码: #inc ...

  4. POJ Ant Counting DP

    dp[i][j]表示前i种蚂蚁组成元素个数为j的集合有多少种. 则dp[i][j] = dp[i-1][j] + dp[i-1][j-1] + ... + dp[i-1][ max(0,j-a[i]) ...

  5. 低版本的无法打开高版本的VM

    低版本VM工具運行高版本VM環境時,會彈出不支持虚拟机配置.例如:使用VM8工具打開VM9配置的VM環境,會彈出下面的提示 在遇到這種情況的時候,一般都會選擇升級VM工具.如果不想升級VM工具,可以通 ...

  6. [学习笔记] 七步从AngularJS菜鸟到专家(4和5):指令和表达式 [转]

    这一篇包含了"AngularJS - 七步从菜鸟到专家"系列的第四篇(指令)和第五篇(表达式). 之前的几篇展示了我们应用的核心组件,以及如何设置搭建一个Angular.js应用.在这一部分,我们会厘 ...

  7. Educational Codeforces Round 10

    A:Gabriel and Caterpillar 题意:蜗牛爬树问题:值得一提的是在第n天如果恰好在天黑时爬到END,则恰好整除,不用再+1: day = (End - Begin - day0)/ ...

  8. 斯坦福第十九课:总结(Conclusion)

    19.1  总结和致谢 欢迎来到<机器学习>课的最后一段视频.我们已经一起学习很长一段时间了.在最后视频中,我想快速地回顾一下这门课的主要内容,然后简单说几句想说的话. 作为这门课的结束时 ...

  9. 【6_100】Same Tree

    Same Tree Total Accepted: 97481 Total Submissions: 230752 Difficulty: Easy Given two binary trees, w ...

  10. glRotate函数

    void glRotate( GLdouble angle, GLdouble x, GLdouble y, GLdouble z ) API说明:angle为旋转角度,单位为度:x,y,z是旋转轴的 ...