大家都知道在我们一开始学习编程语言中的函数时,我们所传入的参数统统为数据类型。所以当我们学习委托的时候难免会有些疑惑,为什么函数传入了一个方法?为什么不在内部调用方法?或者为什么能够传入方法?现在根据我所学的内容来和大家一起解决这些问题。
人是经验型的动物,以往的知识难免会对新所学习的知识造成影响,而且更多的时候我们容易被表象所迷惑。或许我们所看到的的内容并不就像我们所想象的那样,深层次的挖掘或许能找到一个统一不变的模式,解决自己的疑惑。
首先我们应该有这样的认识,在C#中一切类,委托,数据结构都起源于同一个类object,那么任何类型在C#中都是或者可以转化为一个类,那么委托也不例外,看下面的一句代码
接下来我们到反编译器中看一看编译器帮我们生成了什么
从反编译器中我们看到了3个实例函数以及一个构造函数,也就是说,虽然一个委托类型的声明只有一条语句,但是在后台,编译器还是会以一个类的形式维护委托。那么我们向函数传递的的确是委托类型的实例,但是如果理解成传递的是一个类实例或者更有好处。大家应该都知道,函数名代表着代码在内存中存放的一块地址,那么用函数名来初始化委托也就顺理成章了。
那么我们看看如何实例化一个委托的引用
我们看到了new 运算符,我们利用委托声明一引用,并且实例化该引用,我们可以清晰的看到代码与声明一个类实例时完全一致。而x.ToString只是函数的首地址。并不指代代码本身。当然大家有些时候也会见到如下形式的引用声明
我们在反编译器中查看一下,虽然声明方式不同,但是编译器还是会在后台为我们做相同的工作。代码如下:
相信大多数人又这样一种心态,理解了一个难懂的概念建立在我们确实的从这个概念获益,确实的感悟到这个概念的好处。
那么上面的一段代码不应该表现出我们合理的利用了委托,我们费了很大的劲只是使用了委托,原本很简单的一件事我们却绕了很大的圈子。而以上代码并未证明委托的优势,相反给人一种麻烦的感觉。这样并不能让我们设身处地的理解学习委托。
那么我们应该用什么证明委托的优势呢,我想泛型提供了一个很好的平台。接下来我们将用排序算法来证明委托的优势。
冒泡排序相信大家都清楚了解,我们排序一组数据。首先比较数据,然后根据需要调换顺序。问题出现了,我们对整型数据
排序首先是因为编译器清楚的知道二者如何比较。或者说.NET平台已经提供了对简单数据类型的比较算法。如果我们传递了一个对象,编译器就不知道该如何比较了,编译器无法找到对类这一实例的比较算法,如果我们并未实现该算法时。为了实现代码的从用,为了实现以某种始终如一的方式对大多数对象进行一致的处理,我们用到了泛型。泛型的出现使得委托有了一个更广阔的平台。充分发挥了委托的优势。在下面的例子中将使用委托解决特定对象在一个一致算法中的排序问题。
首先我们构造一个类,作为来源数据的类型。添加比较算法。使得能够对两个对象实例进行比较。
接下来是一个一致的算法,它能够实现多种类型数据的排序工作,IList<T> sortArray 是一个T类型的数据源。其中Func<T,T,bool>是一个泛型委托,其中俩个T ,T 类型变量为输入数据,而bool类型数据表示返回类型,它提供了函数的一个一致的模式,即需要两个输入数据,提供一个bool类型的返回值。有关更多泛型的知识可以参看以下MSDN。排序算法不需要对数据类型进行了解,也不需要知道数据的比较方式。但它提供了一个一致的接口实现了,利用委托接受比较函数,实现了对代码的隐藏,使得程序更为灵活。
在主函数中完成排序算法,并输出数据。在这个例子中利用委托传递排序方法,实现了一个支持不同种类实现了比较方法的数据结构的冒泡排序。
委托使得我们可以在需要的地方传入合适的代码,他可以封装某个方法,实现代码灵活的调用。给方法传入数据,我们可以实现对数据的合理处理。给方法传入委托,那么我们可以在某个片段(或者整个方法中)不关心数据的处理方式,而让对数据的处理交给第三方。更何况很多时候我们并不知道该如何对数据进行处理。这样从很大程度上保证了数据的隐秘性。