C#系列:其实委托很简单(下)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#系列:其实委托很简单(下)相关的知识,希望对你有一定的参考价值。

在上一篇博文中,我们知道了委托就是一种用来声明一个变量的数据类型,只不过委托声明的变量可以接受一个方法,只要方法签名保持一致就行了。

 

 今天继续介绍委托。

(一)委托的本质就是class:

为什么说委托的本质就是class呢?我们知道当我们用C#编写完源代码后都要对项目进行编译,我们运行的C#代码实际上都是编译后的代码,编译后的代码我们成为:微软中间代码。

那我们就新建一个项目,在项目中只添加一个class,然后编写我们的C#源代码,然后接着就编译项目。让VS帮我们生成微软中间代码。

所以我们来看看编写一个class编译后的代码是什么样子,那就新建一个项目,里面添加一个Program.cs类文件,如下:

技术分享

好了,接着在Program里写个Main方法,如下:

技术分享

然后编译这个项目,让VS帮我们编译C#源代码,如下:

技术分享

那我们编写的代码已经编译成功了,我们去项目所在文件夹里找到编译后的文件:

技术分享

然后定位到debug文件夹里:

技术分享

上图中,第一个文件就是我们编译后的文件:DemoForDelegate,编译后的文件名和我们新建的项目名称是一致的:DemoForDelegate。

那么现在得到了编译后的文件,这个就包含了我们编译后的中间代码了,所以我们现在需要查看这个文件里代码是什么样子,那就需要有一种相应的工具来查看。

这种工具就是:ILDasm,那我们去找我们电脑的系统盘里找到这个工具,因为我系统装在C盘,所以我去C盘把它找出来:

我找到了,它在这个目录下:C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v10.0A\\bin\\NETFX 4.6.1 Tools

技术分享

然后双击打开它,如下:

技术分享

所以呢,再把我们刚才编译后的项目托进去查看编译后的中间代码是什么样子:

技术分享

之后:

技术分享

我们看到编译后的文件里包含了项目:DemoForDelegate,这个项目唯一的Program类也包含进来了,所以和我们想象中差不多,该有的都有了。

同时,我们看在Program类下面还有.class private auto ansi beforefieldinit ,.ctor:void(),Main:void(string[])这3个成员,它们分别是:Program类,Program类的构造函数,Main方法。我们只要用鼠标双击这个3个成员就可以查看编译后的代码了,我们双击.ctor:void()看看:

技术分享

那么到现在,我们已经知道如何查看C#编译后的代码了,接着回到委托。那么我们在Program类里添加一个委托吧:

技术分享

再编译,然后再ILDasm里查看发生了什么:

技术分享

从上图中我们可以看到委托最终也被编译成了一个同名的类,所以说委托的本质也是一个类。

 

(二)泛型委托:

一般在我们项目中会使用委托,所以我们来定义几个委托:

1 namespace DemoForDelegate
2 {
3     public delegate void delegateInt(int m);
4     public delegate void delegatedouble(double d);
5     public delegate void delegatestring(string str);
6     public delegate void delegatefloat(float f);
7     public delegate void delegatedecimal(decimal d);
8 }

我们定义了5个委托,这5个委托用于接受不同的方法。

但是,我们仔细找下规律就会发现其实这5个委托很相似:返回类型都是void,方法输入参数为1个。不同的是参数的数据类型。那么我想简化一下代码,想写一个通用的委托来取代上面那5个委托,既然它们的差异是参数的数据类型,那么很容易想到用泛型来让代码变得通用,如下:

 1 namespace DemoForDelegate
 2 {
 3     //public delegate void delegateInt(int m);
 4     //public delegate void delegatedouble(double d);
 5     //public delegate void delegatestring(string str);
 6     //public delegate void delegatefloat(float f);
 7     //public delegate void delegatedecimal(decimal d);
 8 
 9     public delegate void MyAction<T>(T arg);
10 }

这样用一个委托就搞定了,所以在我们项目可以这样多定义一些这样的泛型委托:

1 namespace DemoForDelegate
2 {
3     public delegate void MyAction();
4     public delegate void MyAction<T>(T arg);
5     public delegate void MyAction<T1, T2>(T1 arg1, T2 arg2);
6     public delegate void MyAction<T1, T2, T3>(T1 arg1, T2 arg2,T3 arg3);
7     public delegate void MyAction<T1, T2, T3, T4>(T1 arg1, T2 arg2,T3 arg3,T4 arg4);
8     //more...
9 }

上面的委托都没有返回值,那我们再定义一些带返回值的委托吧:

 1 namespace DemoForDelegate
 2 {
 3     public delegate void MyAction();
 4     public delegate void MyAction<T>(T arg);
 5     public delegate void MyAction<T1, T2>(T1 arg1, T2 arg2);
 6     public delegate void MyAction<T1, T2, T3>(T1 arg1, T2 arg2,T3 arg3);
 7     public delegate void MyAction<T1, T2, T3, T4>(T1 arg1, T2 arg2,T3 arg3,T4 arg4);
 8     //more...
 9 
10     //带返回值的委托
11     public delegate TResult MyFunc<out TResult>();
12     public delegate TResult MyFunc<out TResult,in T1>(T1 arg1);
13     public delegate TResult MyFunc<out TResult,in T1,in T2>(T1 arg1,T2 arg2);
14     public delegate TResult MyFunc<out TResult,in T1,in T2,in T3>(T1 arg1, T2 arg2,T3 arg3);
15     //more...
16 
17 }

至于上面的委托名称取:MyAction,MyFunc,哈哈,不解释了,就一个名称而已,你懂。

 

如果大家有关C#技术方面更多的讨论可以加我的一个技术QQ群:240749438。

 

以上是关于C#系列:其实委托很简单(下)的主要内容,如果未能解决你的问题,请参考以下文章

C#异步编程一

快速理解C#高级概念 Delegate委托

对“xxx”类型的已垃圾回收委托进行了回调。这可能会导致应用程序崩溃损坏和数据丢失。向非托管代码传递委托时,托管应用程序必须让这些委托保持活动状态,直到确信不会再次调用它们。 错误解决一例。(代码片段

C#系列你应该知道的委托和事件

C#复习总结细说表达式树

C#进阶系列07 常量和字段