日期:2014-05-18  浏览次数:20968 次

C#中委托和事件
最近学习C#的委托和事件,感觉委托和事件功能很像,都是类似C/C++中的函数指针,这里不过是指向方法的。可是有了委托干嘛还要弄事件,他们的具体区别是什么,各有什么好处!

------解决方案--------------------
我的理解:
1、委托是对方法的规范,也就是“方法”类型的定义。
2、事件是对外部动作的响应,如何响应?由方法的规范来决定,也就是由委托来决定。
楼下补充。。。
------解决方案--------------------
委托、事件在以后的程序开发中肯定会经常使用的,给你推荐一个地址,个人觉得讲的很好。认真看了 我觉得你就基本理解了。
http://www.tracefact.net/CSharp-Programming/Delegates-and-Events-in-CSharp.aspx
------解决方案--------------------
从技术角度说,当你声明如下的事件时:

public event EventHandler Click;

编译器会为你生成一些代码,差不多象这样:

private EventHandler _click;
public event EventHandler Click
{
add { _click += value; }
remove { _click -= value; }
}

这就是说,事件成员本质上是方法。那么,我直接使用公有的委托类型的字段不是更直接么:

public EventHandler Click;

这么写也是可以的,但是这个代码不能用在接口里,因为接口不允许定义字段。当你想为接口定义事件而不能时,会不会觉得它是个很蹩脚的东西?

以上只是从技术角度解释,我更愿意从委托和事件的含义上理解他们的差别。委托是个很技术化的词语,而事件是个更直观的概念。委托是干什么用的,无非是封装个方法而已。如果一个类公开了 Click 委托字段,我会把它理解成“这是点击按钮时会调用的回调方法”,也许还会纠结一下这个字段是不是叫做 ClickCallback 更准确一点,而当它是一个 event 时,它表达的就是“这是点击按钮时引发的事件”,这让我可以更直观的思考,让一堆乱麻似的思维得到一点休息

------解决方案--------------------
很多人不动脑子鹦鹉学舌地不断引用“委托类似C/C++中的函数指针”,但是事实上他们对C/C++中的函数指针能用来干什么并不清楚,或许他们在学校学习的那一点浅薄的C语言知识根本从来没有用过一次“函数指针”。用一个更不理解的概念解释一个不理解的概念,这不是扯淡吗?况且委托多大程度上类似C/C++中的函数指针还是一个问题,其实委托一点也不类似函数指针,恰恰相反,它类似一个抽象基类。

什么是委托?我想搞清楚这个问题必须用你理解的概念去理解。首先回忆下你是怎么理解什么是函数的。我想恐怕没有人教你函数就是汇编语言里面的将数据放入堆栈再跳转的宏(invoke宏)吧。肯定老师会告诉你,函数就是给定一个自变量,通过计算得到另一个变量,产生的变量映射关系。那么程序设计语言上的函数就是一段程序,对输入的参数进行处理,再输出结果。

如果你明白了函数,那么什么是委托?同样,你不需要理解什么“委托类似C/C++中的函数指针”,只有不合格的蹩脚老师才会灌输这个似是而非而且毫无用处的结论。你只要明白,委托的作用就是代表一种函数类型,使得我们可以将函数作为数据传给一个高阶函数。也就是一个函数可以接受另一个函数作为它的自变量,求值。

我们看一个数学上的例子。比如说我们求一个函数的定积分。我们可以写出如下表达式:
f积分(f原函数,上限,下限),这里,f原函数就是一个自变量,同时是一个函数。而f积分这个函数就是一个高阶函数。

委托的作用就是,代表一种函数类型,我们可以这么定义这个函数:
double f积分(OrgFunctionDelegate func, double low, double high);
delegate double OrgFunctionDelegate(double x);
------解决方案--------------------
委托其实可以看成一种数据类型,不过这个数据类型是你自己定义的,
这个数据类型比较特别:它规定了实现它的方法的结构原型,也就是你的事件的类型。
因此:可以说事件是一个特殊的委托类型。
但是事件:可以订阅多次。多次订阅则会调用相应的处理。(可以看看什么是事件轮循)
看代码:
C# code

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace WindowsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            //订阅多次事件
            this.Load += new EventHandler(Form1_Load); //加事件:+1
            this.Load += new EventHandler(Form1_Load1);//加事件:+1
            this.Load += new EventHandler(Form1_Load1);//加事件:+1

            //当事件激发时,C#会轮循事件的订阅。也就是说:我们在往Load事件中加处理方法。
            //参考类似代码:int n=0;n+=1;

            //移除事件
            this.Load -= new EventHandler(Form1_Load1);//-1,减事件。是不是类似我们的:int n=0;n+=1;
        }

        void Form1_Load(object sender, EventArgs e)
        {
            MessageBox.Show("Form1_Load");
        }

        void Form1_Load1(object sender, EventArgs e)
        {
            MessageBox.Show("Form1_Load1");
        }
    }
}