zoukankan      html  css  js  c++  java
  • C#学习之委托和事件

    C#学习中,关于委托和事件的一些见解:

    一.C语言中的函数指针

    想要理解什么是委托,就要先理解函数指针的概念。所谓函数指针,就是指向函数的指针(等于没说-.-)。比如我定义了两个函数square和cube分别用于计算一个数的平方和立方,我再定义函数指针calcu,然后我让calcu指向square,那么调用calcu时就相当于调用了square函数(注意,此处函数指针接受的参数类型及个数要与函数一致)。很好理解吧?不多说,上代码。

     1 #include <stdio.h>
     2 
     3 void square(int x) { printf("square of %d is %d
    ",x,x*x); }
     4 void cube(int x) { printf("cube of %d is %d
    ",x,x*x*x); }
     5 
     6 int main()
     7 {
     8     void (*calcu)(int x);
     9     calcu=square;
    10     calcu(2);
    11 
    12     return 0;
    13 }

    二.C#中委托的实质

    委托又名委托类型,为什么C#弄出这个东西?因为C#是一门比较安全的语言,不允许操作指针,于是我们不能定义函数指针。但想要达到相同的效果,于是定义了委托类型。所谓委托类型,其本质就是C中的指针类型。于是代码变成了这样:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 namespace Delegate
     8 {
     9     class Program
    10     {
    11         static void square(int x) { Console.WriteLine("square of {0} is {1}", x, x * x); }
    12         static void cube(int x) { Console.WriteLine("cube of {0} is {1}", x, x * x * x); }
    13 
    14         delegate void math(int x); //定义委托类型
    15 
    16         static void Main(string[] args)
    17         {
    18             math calcu;
    19             calcu += square;
    20             calcu(2);
    21             Console.ReadKey();
    22         }
    23     }
    24 }

    可以看出,定义委托类型math实际上就相当于定义了void*类型。而委托类型实例化得到的calcu实际上就是函数指针。(说句题外话:定义函数(方法)时要加上static是因为调用函数时并未实例化,只有静态方法能够直接通过类调用)。

    三.委托的使用方法

    我们在上述代码19行后面加上一行代码 calcu+=cube; 运行会发现,square和cube均被调用。可以看出,符号 += 表示绑定方法到委托变量,同理符号 -= 表示取消绑定。可以理解为calcu是void **类型,即它指向了一个数组,数组中的每一项都是函数指针类型,每次调用calcu时,遍历此数组,即依次调用每个绑定的方法。

    四.封装与事件的引入

    下面我们要用面向对象的思想将上述代码进行封装,使其变清晰。

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 namespace Delegate
     8 {
     9     public delegate void math(int x);
    10     public class Calcu
    11     {
    12         public math calcu;
    13     }
    14 
    15     class Program
    16     {
    17         static void square(int x) { Console.WriteLine("square of {0} is {1}", x, x * x); }
    18         static void cube(int x) { Console.WriteLine("cube of {0} is {1}", x, x * x * x); }
    19         
    20         static void Main(string[] args)
    21         {
    22             Calcu c = new Calcu();
    23             c.calcu += square;
    24             c.calcu += cube;
    25             c.calcu(2);
    26             Console.ReadKey();
    27         }
    28     }
    29 }

    由于委托变量是public的,封装的程度很低,在外部可以任意修改。为了改进这个问题,C#引入了事件。

    所谓事件,实际上还是委托的实例化,只是其内部多了一些定义,多了一些限制。其一,事件实际上声明了一个private类型的委托变量,因此在类外无法直接调用。

    于是我们将上述代码的第12行改成这样:

    public event math calcu;

    运行之后25行报错了,因为calcu是private的,不能直接调用。但23,24行并没有报错。那么问题来了,为什么我们可以用+=来给calcu绑定方法呢?

    因为其二,事件还帮我们干了一件事情,就是定义了绑定方法和取消绑定方法的函数,它们是public的,并且将运算符+=,-=重载,和这两个函数对应。

    好了,现在我们要写一个接口函数来完成计算:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 namespace Delegate
     8 {
     9     public delegate void math(int x);
    10     public class Calcu
    11     {
    12         public event math calcu;
    13         public void calculate(int x)
    14         {
    15             calcu(x);
    16         }
    17     }
    18 
    19     class Program
    20     {
    21         static void square(int x) { Console.WriteLine("square of {0} is {1}", x, x * x); }
    22         static void cube(int x) { Console.WriteLine("cube of {0} is {1}", x, x * x * x); }
    23         
    24         static void Main(string[] args)
    25         {
    26             Calcu c = new Calcu();
    27             c.calcu += square;
    28             c.calcu += cube;
    29             c.calculate(2);
    30             Console.ReadKey();
    31         }
    32     }
    33 }

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

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

    (转载他人文章,http://www.open-open.com/lib/view/open1455424278761.html)

  • 相关阅读:
    <转>MSDN上关于XPath的语法文章
    <转>正则表达式语法
    <转>反射技术的简单介绍
    <转>css中用expression实现js的onmouseover/onmouseout事件
    <转>在xslt中实现split方法对查询字符串进行分隔
    <转>SQL Server中的XML数据进行insert、update、delete
    <转>VS2010项目转换到VS2008下方法
    <转>在xslt 1.0 中取得当前时间
    C# 发送邮件的Helper类
    DataTable 类的学习笔记
  • 原文地址:https://www.cnblogs.com/China-YangGISboy/p/6486710.html
Copyright © 2011-2022 走看看