委托、lambda表达式和事件(一)

     委托是寻址方法的.NET版本。在C++中,函数指针只不过是一个指向内存位置的指针,它不是类型完全的。无法判断这个指针实际指向什么,像参数和返回类型等项就更无从知晓。而.NET委托完全不同,委托是类型安全的类,它定义返回类型和参数的类型。委托类不仅包含方法的引用,也可以包含对多个方法的引用。

     lambda表达式与委托直接相关。当参数是委托类型时,就可以使用lambad表达式实现委托引用的方法。

1、委托

当要把方法传送给其他方法时,需要使用委托。委托定义:

int i=int.Parse("99");

(1) 启动线程和任务——在C#中,可告诉计算机并行运行某些新的执行系列,同时运行当前的任务。这种系列就称为线程,在其中一个基类System.Threading.Thread的一个实例上使用方法Start(),便可启动一个线程。必须为计算机提供开始启动的方法的细节,即Thread类的构造函数必须带有一个参数,该参数定义线程调用的方法。

(2) 通用库类——许多库包含执行各种标准任务的代码。

(3) 事件——一般是通知代码发生什么事件。GUI编程主要处理事件。在引用事件时,运行库需要知道应执行哪个方法。这就需要把处理事件的方法作为一个参数传递给委托。

    在C和C++总,只能提取函数的地址,并作为一个参数传递它。若要传递方法,就必须把方法的细节封装在一种新类型的对象中,即委托。委托只是一种特殊类型的对象,其特殊之处在于,以前定义的所有对象包含数据,而委托包含的只是一个或多个方法的地址。

1) 声明委托

C#中使用一个类时,分两个阶段。首先,需要定义这个类,即告诉编译器这个类由什么字段和方法组成。然后(除非只使用静态方法),实例化类的一个对象。当然使用委托时,也需要两个步骤。首先必须定义要使用的委托,对于委托,定义它就是告诉编译器这种类型的委托表示哪种类型的方法。然后,必须创建该委托的一个或多个实例。编译器在后台将创建表示该委托的一个类。定义委托的语法如下:

delegate void IntMethodInvoker(int x);

理解委托一个要点是它们的类型安全性非常高。在定义委托时,必须给出它所表示的方法的签名和返回类型等全部细节。

实际上,“定义一个委托”是指“定义一个新类”。委托实现为派生自基类System.MulticastDelegate的类,System.MulticastDelegate又派生自基类System.Delegate。C#编译器能识别这个类,会使用其委托语法,对此不需要了解这个类的具体执行情况。这是C#与基类共同合作,使编程更易完成的另一个范例。

2) 使用委托

private delegate string GetAString();
static void Main()
{
   int x=40;
   GetAString firstStringMethod=new GetAString(x.ToString);
   Console.WriteLine("String is {0}",firstStringMethod());
   //With firstStringMethod initialized to x.ToString();
   //the above statement is equivalent to saying
   //Console.WriteLine("String is {0}",x.ToString());
}

在C#中,委托在语法上总是接受一个参数的构造函数,这个参数就是委托引用一个字符串的方法来初始化firstStringMethod变量,就会产生一个编译错误。

注意:因为int.ToString()是一个实例方法(不是静态方法),所以需要指定实例(x)和方法名来正确地初始化委托。

示例用GetAString委托的一个新实例初始化GetAString类型的firstStringMethod变量:

GetAString firstStringMethod=new GetAString(x.ToString);

3) Action<T>和Func<T>委托

泛型Action<T>委托表示引用一个void返回类型的方法。

下面的代码是参数double类型,返回类型double:

delegate double DoubleOp(doule x);

除声明自定义DoubleOp之外,还可以使用Func<int T,out TResult>委托。可以声明该委托类型的变量,或者该委托类型的数组,如下所示:

Func<double,double>[] operations=
{
  MathOperations.MultiplyByTwo,
  MathOperations.Square
};

使用它,并将ProcessAndDisplayNumber()方法作为参数:

static void ProcessAndDisplayNumber(Func<double,double>action,
                                              double Value)
{
  double result=action(value);
  Console.WriteLine("Value is {0},result of operation is {1}",
                                             value,result);
}

4) BubbleSorter示例

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

bool swapped=true;
do
{
  swapped=false;
  for(int i=0;i<sortArray.Length-1;i++)
  { 
    if(sortArray[1]>sortArray[i+1]))  //problem with this test
    {
      int temp=sortArray[i];
      sortArray[i]=sortArray[i+1];
      sortArray[i+1]=temp;
      swapped=true;
     }
    }
}while (swapped);

5) 多播委托

调用委托的次数与调用方法的次数相同。如果要调用多个方法,就需要多次显式调用这个委托。但是,委托也可以包含多个方法。这种委托称为多播委托。如果调用多播委托,就可以按顺序连续调用多个方法。为此,委托的签名就必须返回void;否则,就只能得到委托调用的最后一个方法的结果。

可以使用返回类型为void的Action<double>委托:

class Program
{
  static void Main()
  {
    Action<double>operations=MathOperations.MultiplyByTwo;
    operations+=MathOperations.Square;
    Action<double>operation1=MathOperations.MultiplyByTwo;
    Action<double>operation2=MathOperations.Square;
    Action<double>operations=operation1 + operation2;
}

6) 匿名方法

匿名方法是用作委托的参数的一段代码。用匿名方法定义委托的语法与前面的定义并没有区别。但在实例化委托时,便有区别。下面代码说明使用匿名方法:

using System;

namespace Wrox.ProCSharp.Delegates
{
  class Program
  {
    static void Main()
    { 
      string mid=",middle part,";
   
       Func<string,string>annonDel=delegate(string param)
       {
          param +=mid;
          param +="and this was added to the string.";
          return param;
       };
       Console.WriteLine(anonDel("Start of string"));
     }
    }
}

参考

C#高级编程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值