最近刚刚接触C#,学到事件与委托部分无法理解,于是上网查阅了各种资料,终于明白了一些,在此进行总结。

一.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(); return ;
}

二.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();
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();
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();
Console.ReadKey();
}
}
}

  至此,基本概念已经清晰。

  想来,使用事件会让人不得不将对象封装起来,这应该就是面向对象思想的体现吧。

参考资料:http://www.tracefact.net/CSharp-Programming/Delegates-and-Events-in-CSharp.aspx

C#委托与事件初探的更多相关文章

  1. C#委托与事件的简单使用

    前言:上一篇博文从原理和定义的角度介绍了C#的委托和事件.本文通过一个简单的小故事,来说明C#委托与事件的使用方法及其方便之处. 在阅读本文之前,需要你对委托和事件的基本概念有所了解.如果你是初次接触 ...

  2. .NET面试题系列[7] - 委托与事件

    委托和事件 委托在C#中具有无比重要的地位. C#中的委托可以说俯拾即是,从LINQ中的lambda表达式到(包括但不限于)winform,wpf中的各种事件都有着委托的身影.C#中如果没有了事件,那 ...

  3. .NET基础拾遗(4)委托、事件、反射与特性

    Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理基础 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开 ...

  4. [转载]C#深入分析委托与事件

    原文出处: 作者:风尘浪子 原文链接:http://www.cnblogs.com/leslies2/archive/2012/03/22/2389318.html 同类链接:http://www.c ...

  5. [转载]C#委托和事件(Delegate、Event、EventHandler、EventArgs)

    原文链接:http://blog.csdn.net/zwj7612356/article/details/8272520 14.1.委托 当要把方法作为实参传送给其他方法的形参时,形参需要使用委托.委 ...

  6. C#委托与事件

    一.在控制台下使用委托和事件 我们都知道,C#中有"接口"这个概念,所谓的"接口"就是定义一套标准,然后由实现类来具体实现其中的方法,所以说"接口,是 ...

  7. C#之委托与事件

    委托与事件 废话一堆:网上关于委托.事件的文章有很多,一千个哈姆雷特就有一千个莎士比亚,以下内容均是本人个人见解. 1. 委托 1.1 委托的使用 这一小章来学习一下怎么简单的使用委托,了解一些基本的 ...

  8. [ASP.NET MVC 大牛之路]02 - C#高级知识点概要(1) - 委托和事件

    在ASP.NET MVC 小牛之路系列中,前面用了一篇文章提了一下C#的一些知识点.照此,ASP.NET MVC 大牛之路系列也先给大家普及一下C#.NET中的高级知识点.每个知识点不太会过于详细,但 ...

  9. .NET委托和事件

    .net学习之委托和事件   1.什么是委托 通俗的说:委托就是一个能够存储符合某种格式(方法签名)的方法的指针的容器 上传图片: 2.委托语法 准备一个方法:string Hello(string ...

随机推荐

  1. Unity NGUI添加UIRoot

    导入NGUI包后,菜单多出一个选项 "NGUI",选择其子选项 "options" -- "Reset Prefab ToolBar" ,在 ...

  2. python 使用pymssql连接sql server数据库

    python 使用pymssql连接sql server数据库   #coding=utf-8 #!/usr/bin/env python#------------------------------ ...

  3. java 保留字符串数字的位数,不够前面补0

    @Test public void test() { this.printToConsole(autoGenericCode("10011")); this.printToCons ...

  4. php实验5数组

    1.自定义两个数组,分别为索引数组和关联数组,每个数组必须至少有4个元素,使用print_r( )函数输出数组元素. 2.编写一个随机抽奖程序,示例运行结果如下: 3.定义一个三维数组$categor ...

  5. 461. Hamming Distance

    https://leetcode.com/problems/hamming-distance/ 将两个二进制数比较,输出不同位数的个数 Input: x = 1, y = 4 Output: 2 Ex ...

  6. Java 基础高级2 网络编程

    1.协议的概念:通信双方事先约定好的通信规则 2七层网络通信协议:应用成,表示层,会话层,传输层,网络层,数据链路层 3.TCP/IP协议:点对点通信,三层握手,安全有保证 4.UDP协议;广播协议, ...

  7. ASP中Lable控件的定位问题

    问题:Lable控件的定位问题:找了好久都没找到可以将Lable控件定位的办法,网上说可以将修改position这个属性来实现定位,可是我始终没找到这个属性. (1)首先,在源代码中添加 style ...

  8. linux的相关指令命令

    ls:查看当前所在的目录 whoami:查看当前所在的用户名 who:(查看所有的正在使用的用户名) id:唯一的识别编号(组所在的识别编号) uname  -a:显示当前操作系统的版本 cd:切换工 ...

  9. CSS 清除默认样式

    通常有以下几句就够了: *{margin:0;padding:0} li{list-style:none} img{vertical-align:top;border:none} 如果你想写全也可以: ...

  10. Mahout推荐算法API详解

    转载自:http://blog.fens.me/mahout-recommendation-api/ Hadoop家族系列文章,主要介绍Hadoop家族产品,常用的项目包括Hadoop, Hive, ...