关于C#中委托的一点理解

C#中委托是一种类型。可以这么笼统的理解:int型变量代表一个整型,而委托类型的变量代表一个方法的地址(将方法名称传入constructor并实例化该委托变量)。

--By Brisk Yu

 

1 为何要使用委托

我觉得网上关于什么现实生活的举例并不好,还是要从程序的本质去理解:

1)程序是由事件驱动的。

2)事件发生时,操作系统需要知道事件对应的处理函数。例如,用户按下鼠标时操作系统需要知道此时该做什么,是关闭窗口呢,还是打开某个文件呢?当网卡接收到数据包时操作系统也需要知道此时该做什么,是往上层传输呢,还是丢弃呢?

3)因此,我们需要将事件对应的处理函数提前告知操作系统(向操作系统注册),操作系统在发生该事件时,调用对应的处理函数,这便是回调,对应的处理函数也被称为回调函数

4)那么我们如何向操作系统注册回调函数呢(如何让操作系统知道发生对于事件它该干嘛呢)?对于C++,我们使用pointer,而对于C#,我们使用delegate。

 

2 如何使用委托

先从最基本的创建委托的方法开始,逐步变换为使用匿名方法和lambda expression。

1)最原始用法,用方法名初始化一个委托类型变量,调用该委托类型变量,执行承载的方法:

public delegate int SomeDelegate(int i);

int SomeFunction1(int i) { 
    Console.WriteLine("func1"+i);
    return 3; 
}

。。。Main Function
{
    SomeDelegate sd = new SomeDelegate(SomeFunction1);
    sd(2);
}

 

2)如1)中,如果我们使用委托都需要定义一个委托类型比较麻烦,因此我们使用匿名委托:

删去1)中的

public delegate int SomeDelegate(int i);

并将main function中的代码改为:

Func<int, int> sd= new Func<int, int>(SomeFunction1);
sd(2);

Func和Action是C#为我们定义好了委托类型。Func指有返回参数的委托类型,其<>中最后一个参数既是返回参数的类型;Action指无返回参数的委托类型。

 

3)既然定义委托类型的代码可以拿掉,那么相应的方法声明与定义的语句也可以拿掉:

删去1)中的方法声明与定义的语句:

int SomeFunction1(int i) { 
    Console.WriteLine("func1"+i);
    return 3; 
}

将main function 中的代码改为:

Func<int, int> sd = new Func<int, int>(delegate (int s) { 
    Console.WriteLine("匿名方法" + s); 
    return 88; 
});
int i = sd(2);

此时,Func()中的代码称为匿名方法,即没有方法名。

 

4)我们对3)中的代码进一步修改,将匿名方法改为lambda表达式。(lambda表达式是匿名方法的一种表示方法)

将mian function中的代码改为:

Func<int, int> sd = new Func<int, int>(s=> { 
    Console.WriteLine("匿名方法"+s);
    return 88; 
});
int i = sd(2);

此时,对于lambda表达式,编译器会自动判断其类型,因此无需特指其类型。

 

3 实际应用

我们参考一下winform中鼠标点击事件响应是如何实现的

1)在System命名空间中定义一个委托类型

namespace System
{
    //
    // 摘要:
    //     表示将用于处理不具有事件数据的事件的方法。
    //
    // 参数:
    //   sender:
    //     事件源。
    //
    //   e:
    //     不包含事件数据的对象。
    [ComVisible(true)]
    public delegate void EventHandler(object sender, EventArgs e);
}

2)在Control.cs(所有控件的父类)中定义一个EventHandler型的委托Click

public event EventHandler Click;

注:这里用到了event关键字,表明这个委托是一个事件。其实是指一簇委托。如果理解不了姑且将event拿掉来看。

 

3)编写鼠标点击事件响应代码

private void buttonStart_Click(object sender, EventArgs e)
{
    //TODO
}

 

4)用3)中方法实例化一个委托赋给Click

this.buttonStart.Click += new System.EventHandler(this.buttonStart_Click);

至此,程序便可以响应buttonStart这个按钮的响应事件了。更加具体的操作会深入到操作系统中,这里不再叙述。

--By Brisk Yu

posted @ 2018-12-18 15:58  Brisk  阅读(1673)  评论(0编辑  收藏  举报