最近刚刚接触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. EFUpdate

    using System; using System.Collections.Generic; using System.Configuration; using System.Data; using ...

  2. 49. 3种方法实现复杂链表的复制[clone of complex linked list]

    [本文链接] http://www.cnblogs.com/hellogiser/p/clone-of-complex-linked-list.html [题目] 有一个复杂链表,其结点除了有一个ne ...

  3. 获取本地的IP地址(内网)

    方法一 public static String getLocalIpAddress() { try { for (Enumeration<NetworkInterface> en = N ...

  4. java.lang.IllegalStateException: Cannot add header view to list -- setAdapter has already been called.

    分析:android 4.2.X及以下的版本,addHeaderView必须在setAdapter之前,否则会抛出IllegalStateException. android 4.2.X(API 17 ...

  5. Python之路,Day7 - Python基础7 面向对象

    本节内容:   面向对象编程介绍 为什么要用面向对象进行开发? 面向对象的特性:封装.继承.多态 类.方法.     引子 你现在是一家游戏公司的开发人员,现在需要你开发一款叫做<人狗大战> ...

  6. 如何去掉MyEclipse中的空格符,回车符?

    我前几天不小心把空格符合回车符显示了出来,如图: 天啊,看了两天以后,我感觉整个人都不行了,眼花缭乱,于是就各种尝试,想要去掉,就有了如下方法,其实很简单 在eclipse中的菜单的 window-& ...

  7. abstract与interface的区别

    abstract的用法: //通过abstract 关键字修饰的类叫抽象类. abstract class Animal { String name; String color; abstract p ...

  8. angular之上滑换页指令

    healthmallDirectives.directive("goodsTopRefresh", ['$window',function ($window) { return { ...

  9. mysql 列类型

  10. [leetcode] 提醒整理之进制

    12. Integer to Roman Given an integer, convert it to a roman numeral. Input is guaranteed to be with ...