C#委托与事件初探
2016-02-14 10:08
477 查看
最近刚刚接触C#,学到事件与委托部分无法理解,于是上网查阅了各种资料,终于明白了一些,在此进行总结。
一.C语言中的函数指针
想要理解什么是委托,就要先理解函数指针的概念。所谓函数指针,就是指向函数的指针(等于没说-.-)。比如我定义了两个函数square和cube分别用于计算一个数的平方和立方,我再定义函数指针calcu,然后我让calcu指向square,那么调用calcu时就相当于调用了square函数(注意,此处函数指针接受的参数类型及个数要与函数一致)。很好理解吧?不多说,上代码。
二.C#中委托的实质
委托又名委托类型,为什么C#弄出这个东西?因为C#是一门比较安全的语言,不允许操作指针,于是我们不能定义函数指针。但想要达到相同的效果,于是定义了委托类型。所谓委托类型,其本质就是C中的指针类型。于是代码变成了这样:
可以看出,定义委托类型math实际上就相当于定义了void*类型。而委托类型实例化得到的calcu实际上就是函数指针。(说句题外话:定义函数(方法)时要加上static是因为调用函数时并未实例化,只有静态方法能够直接通过类调用)。
三.委托的使用方法
我们在上述代码19行后面加上一行代码 calcu+=cube; 运行会发现,square和cube均被调用。可以看出,符号 += 表示绑定方法到委托变量,同理符号 -= 表示取消绑定。可以理解为calcu是void **类型,即它指向了一个数组,数组中的每一项都是函数指针类型,每次调用calcu时,遍历此数组,即依次调用每个绑定的方法。
四.封装与事件的引入
下面我们要用面向对象的思想将上述代码进行封装,使其变清晰。
由于委托变量是public的,封装的程度很低,在外部可以任意修改。为了改进这个问题,C#引入了事件。
所谓事件,实际上还是委托的实例化,只是其内部多了一些定义,多了一些限制。其一,事件实际上声明了一个private类型的委托变量,因此在类外无法直接调用。
于是我们将上述代码的第12行改成这样:
这句代码会被编译器解释成private math calcu和一些方法。
运行之后25行报错了,因为calcu是private的,不能直接调用。但23,24行并没有报错。那么问题来了,为什么我们可以用+=来给calcu绑定方法呢?
因为其二,事件还帮我们干了一件事情,就是定义了绑定方法和取消绑定方法的函数,它们是public的,并且将运算符+=,-=重载,和这两个函数对应。
好了,现在我们要写一个接口函数来完成计算:
至此,基本概念已经清晰。
想来,使用事件会让人不得不将对象封装起来,这应该就是面向对象思想的体现吧。
参考资料:http://www.tracefact.net/CSharp-Programming/Delegates-and-Events-in-CSharp.aspx
一.C语言中的函数指针
想要理解什么是委托,就要先理解函数指针的概念。所谓函数指针,就是指向函数的指针(等于没说-.-)。比如我定义了两个函数square和cube分别用于计算一个数的平方和立方,我再定义函数指针calcu,然后我让calcu指向square,那么调用calcu时就相当于调用了square函数(注意,此处函数指针接受的参数类型及个数要与函数一致)。很好理解吧?不多说,上代码。
#include <stdio.h> void square(int x) { printf("square of %d is %d\n",x,x*x); } void cube(int x) { printf("cube of %d is %d\n",x,x*x*x); } int main() { void (*calcu)(int x); calcu=square; calcu(2); return 0; }
二.C#中委托的实质
委托又名委托类型,为什么C#弄出这个东西?因为C#是一门比较安全的语言,不允许操作指针,于是我们不能定义函数指针。但想要达到相同的效果,于是定义了委托类型。所谓委托类型,其本质就是C中的指针类型。于是代码变成了这样:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Delegate { class Program { static void square(int x) { Console.WriteLine("square of {0} is {1}", x, x * x); } static void cube(int x) { Console.WriteLine("cube of {0} is {1}", x, x * x * x); } delegate void math(int x); //定义委托类型 static void Main(string[] args) { math calcu; calcu += square; calcu(2); Console.ReadKey(); } } }
可以看出,定义委托类型math实际上就相当于定义了void*类型。而委托类型实例化得到的calcu实际上就是函数指针。(说句题外话:定义函数(方法)时要加上static是因为调用函数时并未实例化,只有静态方法能够直接通过类调用)。
三.委托的使用方法
我们在上述代码19行后面加上一行代码 calcu+=cube; 运行会发现,square和cube均被调用。可以看出,符号 += 表示绑定方法到委托变量,同理符号 -= 表示取消绑定。可以理解为calcu是void **类型,即它指向了一个数组,数组中的每一项都是函数指针类型,每次调用calcu时,遍历此数组,即依次调用每个绑定的方法。
四.封装与事件的引入
下面我们要用面向对象的思想将上述代码进行封装,使其变清晰。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Delegate { public delegate void math(int x); public class Calcu { public math calcu; } class Program { static void square(int x) { Console.WriteLine("square of {0} is {1}", x, x * x); } static void cube(int x) { Console.WriteLine("cube of {0} is {1}", x, x * x * x); } static void Main(string[] args) { Calcu c = new Calcu(); c.calcu += square; c.calcu += cube; c.calcu(2); Console.ReadKey(); } } }
由于委托变量是public的,封装的程度很低,在外部可以任意修改。为了改进这个问题,C#引入了事件。
所谓事件,实际上还是委托的实例化,只是其内部多了一些定义,多了一些限制。其一,事件实际上声明了一个private类型的委托变量,因此在类外无法直接调用。
于是我们将上述代码的第12行改成这样:
public event math calcu;
这句代码会被编译器解释成private math calcu和一些方法。
运行之后25行报错了,因为calcu是private的,不能直接调用。但23,24行并没有报错。那么问题来了,为什么我们可以用+=来给calcu绑定方法呢?
因为其二,事件还帮我们干了一件事情,就是定义了绑定方法和取消绑定方法的函数,它们是public的,并且将运算符+=,-=重载,和这两个函数对应。
好了,现在我们要写一个接口函数来完成计算:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Delegate { public delegate void math(int x); public class Calcu { public event math calcu; public void calculate(int x) { calcu(x); } } class Program { static void square(int x) { Console.WriteLine("square of {0} is {1}", x, x * x); } static void cube(int x) { Console.WriteLine("cube of {0} is {1}", x, x * x * x); } static void Main(string[] args) { Calcu c = new Calcu(); c.calcu += square; c.calcu += cube; c.calculate(2); Console.ReadKey(); } } }
至此,基本概念已经清晰。
想来,使用事件会让人不得不将对象封装起来,这应该就是面向对象思想的体现吧。
参考资料:http://www.tracefact.net/CSharp-Programming/Delegates-and-Events-in-CSharp.aspx
相关文章推荐
- c#实现简单金山打字小游戏(源码)
- 【C#基础】初相识——初步认识C#
- C#中数组、ArrayList和List三者的区别
- C#成神之路<19> C#使用磁盘数据文件(3)
- C#设计模式——模板方法模式
- C#写计算器实例
- 单例模式
- C#设计模式——建造者模式
- 学习C# 继承 封装 多态
- 关于C#未能从程序集XXX加载XXX类型问题的解决方法
- c# enum の値を対応
- C#字典
- C#发送邮件时提示:“不允许使用邮箱名称。服务器响应为:”的错误解决办法
- C#里面Attribute的使用方法
- C# 的三种序列化方法
- C#事件触发机制
- c#基本知识:泛型集合的使用
- C#机房重构——万事开头难(一)
- Atitit. C#.net clr 2.0 4.0新特性
- Atitit. C#.net clr 2.0 4.0新特性