第6章 委托和事件(2)

2020-02-22 11:00

? 158 ? 第Ⅰ部分 C# 语 言 6.2 匿名方法

到目前为止,要想使委托工作,方法必须已经存在(即委托是用方法的签名定义的)。但使用委托还有另外一种方式:即通过匿名方法。匿名方法是用作委托参数的一个代码块。

用匿名方法定义委托的语法与前面的定义并没有什么区别。但在实例化委托时,就有区别了。下面是一个非常简单的控制台应用程序,说明了如何使用匿名方法:

namespace ConsoleApplication1 {

class Program {

delegate string delegateTest(string val);

static void Main(string[] args) {

string mid = \

delegateTest anonDel = delegate(string param) {

param += mid;

param += \ return param; };

Console.WriteLine(anonDel(\ } } }

委托delegateTest定义为一个类级变量,它带一个字符串参数。有区别的是Main方法。在定义anonDel时,不是传送已知的方法名,而是使用一个简单的代码块:

{

param += mid;

param += \ return param; };

可以看出,该代码块使用方法级的字符串变量mid,该变量是在匿名方法的外部定义的,并添加到要传送的参数中。接着代码返回该字符串值。在调用委托时,把一个字符串传送为参数,将返回的字符串输出到控制台上。

匿名方法的优点是减少了系统开销。方法仅在由委托使用时才定义。在为事件定义委托时,这是非常显然的。(本章后面探讨事件。)这有助于降低代码的复杂性,尤其是定义了好几个方

第6章 委托和事件 ? 159 ? 法时,代码会显得比较简单。

在使用匿名方法时,必须遵循两个规则。在匿名方法中不能使用跳转语句跳到该匿名方法的外部,反之亦然:匿名方法外部的跳转语句不能跳到该匿名方法的内部。

在匿名方法内部不能访问不安全的代码。另外,也不能访问在匿名方法外部使用的ref和out参数。但可以使用在匿名方法外部定义的其他变量。

6.2.1 简单的委托示例

在这个示例中,定义一个类MathsOperations,它有两个静态方法,对double类型的值执行两个操作,然后使用该委托调用这些方法。这个数学类如下所示:

class MathsOperations {

public static double MultiplyByTwo(double value) {

return value*2; }

public static double Square(double value) {

return value*value; } }

下面调用这些方法:

using System;

namespace SimpleDelegate {

delegate double DoubleOp(double x);

class MainEntryPoint {

static void Main() {

DoubleOp [] operations = {

new DoubleOp(MathsOperations.MultiplyByTwo), new DoubleOp(MathsOperations.Square) };

for (int i=0 ; i

Console.WriteLine(\

? 160 ? 第Ⅰ部分 C# 语 言 ProcessAndDisplayNumber(operations[i], 2.0); ProcessAndDisplayNumber(operations[i], 7.94); ProcessAndDisplayNumber(operations[i], 1.414); Console.WriteLine(); } }

static void ProcessAndDisplayNumber(DoubleOp action, double value) {

double result = action(value); Console.WriteLine(

\ }

在这段代码中,实例化了一个委托数组DoubleOp (记住,一旦定义了委托类,就可以实例化它的实例,就像处理一般的类那样—— 所以把一些委托的实例放在数组中是可以的)。该数组的每个元素都初始化为由MathsOperations类执行的不同操作。然后循环这个数组,把每个操作应用到3个不同的值上。这说明了使用委托的一种方式—— 把方法组合到一个数组中,这样就可以在循环中调用不同的方法了。

这段代码的关键一行是把委托传递给ProcessAndDisplayNumber()方法,例如:

ProcessAndDisplayNumber(operations[i], 2.0);

其中传递了委托名,但不带任何参数,假定operations[i]是一个委托,其语法是: ● operations[i]表示“这个委托”。换言之,就是委托代表的方法。 ● operations[i](2.0)表示“调用这个方法,参数放在括号中”。 ProcessAndDisplayNumber()方法定义为把一个委托作为其第一个参数:

static void ProcessAndDisplayNumber(DoubleOp action, double value)

在这个方法中,调用:

double result = action(value);

这实际上是调用action委托实例封装的方法,其返回结果存储在result中。 运行这个示例,得到如下所示的结果:

SimpleDelegate Using operations[0]:

Value is 2, result of operation is 4 Value is 7.94, result of operation is 15.88 Value is 1.414, result of operation is 2.828

Using operations[1]:

Value is 2, result of operation is 4

Value is 7.94, result of operation is 63.0436

第6章 委托和事件 Value is 1.414, result of operation is 1.999396

? 161 ? 如果在这个例子中使用匿名方法,就可以删除第一个类MathOperations。Main方法应如下所示:

static void Main() {

DoubleOp multByTwo = delegate(double val) {return val * 2;} DoubleOp square = delegate(double val) {return val * val;}

DoubleOp [] operations = {multByTwo, square};

for (int i=0 ; i

Console.WriteLine(\ ProcessAndDisplayNumber(operations[i], 2.0); ProcessAndDisplayNumber(operations[i], 7.94); ProcessAndDisplayNumber(operations[i], 1.414); Console.WriteLine(); } }

运行这个版本,结果与前面的例子相同。其优点是删除了一个类。

6.2.2 BubbleSorter示例

下面的示例将说明委托的用途。我们要编写一个类BubbleSorter,它执行一个静态方法Sort(),这个方法的第一个参数是一个对象数组,把该数组按照升序重新排列。换言之,假定传递的是int数组:{0, 5, 6, 2, 1},则返回的结果应是{0, 1, 2, 5, 6}。

冒泡排序算法非常著名,是一种排序的简单方法。它适合于一小组数字,因为对于大量的数字(超过10个),还有更高效的算法。冒泡排序算法重复遍历数组,比较每一对数字,按照需要交换它们的位置,把最大的数字逐步移动到数组的最后。对于给int排序,进行冒泡排序的方法如下所示:

for (int i = 0; i < sortArray.Length; i++) {

for (int j = i + 1; j < sortArray.Length; j++) {

if (sortArray[j] < sortArray[i]) // problem with this test {

int temp = sortArray[i]; // swap ith and jth entries sortArray[i] = sortArray[j]; sortArray[j] = temp; } } }

? 162 ? 第Ⅰ部分 C# 语 言 它非常适合于int,但我们希望Sort()方法能给任何对象排序。换言之,如果某段客户机代码包含Currency结构数组或其他类和结构,就需要对该数组排序。这样,上面代码中的if(sortArray[j] < sortArray[i])就有问题了,因为它需要比较数组中的两个对象,看看哪一个更大。可以对int进行这样的比较,但如何对直到运行期间才知道或确定的新类进行比较?答案是客户机代码知道类在委托中传递的是什么方法,封装这个方法就可以进行比较。

定义如下的委托:

delegate bool CompareOp(object lhs, object rhs);

给Sort方法指定下述签名:

static public void Sort(object [] sortArray, CompareOp gtMethod)

这个方法的文档说明强调,gtMethod必须表示一个静态方法,该方法带有两个参数,如果第二个参数的值“大于”第一个参数(换言之,它应放在数组中靠后的位置),就返回true。

注意:

这里使用的是委托,但也可以使用接口来解决这个问题。.NET提供的IComparer接口就用于此目的。但是这里使用委托是因为这种问题本身要求使用委托。

设置完毕后,下面定义类BubbleSorter:

class BubbleSorter {

static public void Sort(object [] sortArray, CompareOp gtMethod) {

for (int i=0 ; i

for (int j=i+1 ; j

if (gtMethod(sortArray[j], sortArray[i])) {

object temp = sortArray[i]; sortArray[i] = sortArray[j]; sortArray[j] = temp; } } } } }

为了使用这个类,需要定义一些其他类,建立要排序的数组。在本例中,假定Mortimer Phones移动电话公司有一个员工列表,要对照他们的薪水进行排序。每个员工分别由类Employee的一个实例表示,如下所示:

class Employee


第6章 委托和事件(2).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:教师资格证考试中学综合素质考点

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: