委托

来源:互联网 发布:网文枪手 知乎 编辑:程序博客网 时间:2024/06/05 16:25

     之前有学习过C++,但是没有实际练习过c#,所以今天又学习了下。

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

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

   下面说明如何通过LAMBDA表达式实现委托调用,并阐述.NET如何将委托用作实现事件的方式。

  

        委托


        当要把方法传递给其他方法时,需要使用委托。要了解它们的含义,可以看下面的代码:

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

         我们习惯于把数据作为 参数传递给方法,如上面的例子所示。所以,给方法传递另一个方法听起来有点奇怪,而有时某个方法执行的操作并不是针对数据进行的,而是要对另一个方法进行操作。更麻烦的是在编译时我们不知道第二个方法是什么 ,这个信息只能在运行时才能得到,所以需要把第二个方法作为参数传递给第一个方法。这听起来很令人迷惑,下面用几个示例来说明:

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

        通用库类---许多库包含执行各种标准任务的代码。这些库通常可以自我包含。这样在编写库时 ,就会知道任务该如何执行。但是有时在任务中包含 子任务,只有使用该库的客户端代码才知道如何执行这些子任务。例如,编写一个类,它带有一个对象数组,并把它们按升序排列。但是,排序的部分过程会涉及重复使用数组中的两个对象,比较它们,看看哪一个应该在前面。如果 要编写 的类必须能对任何对象数组排序,就无法提前告诉计算机应如何比较对象。处理类中对象数组的 客户端就必须给类传递某个可以调用并且进行这种比较的合适方法的细节。

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

    

       声明委托


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

      定义委托的语法如下:

       delegate void IntMethodInvoker(int x);

       在这个示例中,定义了一委托IntMethodInvoker,并指定该委托的每个实例都可以包含一个方法的引用,该方法带有一个int参数,并返回void 。理解委托 的一个要点是它们的类型安全性非常高。在定义委托时,必须给出它所表示的方法的签名和返回类型等全部细节。

      理解委托的 一种好方式是把委托当作这个一个事情,它给方法的签名和返回类型指定名称。

      假定要定义一个委托TwoLongsOp,该委托表示的方法有两个long型参数,返回类型为double,可以编写如下代码:

      delegate double TwoLongsOp(lnog first,long second);

      或者要定义 一个委托,它表示的方法不包含参数,返回一个string型的值,可以编写如下 代码:

     delegate string GetAString();

      其语法类似于方法的定义,但没有方法体,定义的前面要加上关键字delegate.因为定义委托其本上是定义一个新类,所以可以在定义类的任何相同地方定义委托,也就是说,可以在另一个类的内部定义,也可以在任何类的外部定义,还可以 在名称空间中把委托定义为顶层对象 。根据定义 的可见性,和委托的作用域,可以在委托上应用任意常见的访问修饰符:public /private/protected等:

      public delegate string GetAString();

       在创建委托的实例时,所创建的委托的实例仍称为委托。


       使用委托

       下面的代码使用委托。

          private delegate string GetAString();

         static void main()

         {

                       int x=0;

                      GetAString     firstStringMethod= new  GetAString( x.ToString):

                      Console.WriteLine("String is{0}",firstStringMethod());

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

         }

       实际上给委托实例提供圆括号与调用委托类的Invoke()方法安全相同。因为firstStringMethod

         是委托类型的一个变量,所以C#编译器会用firstStringMethod.Invoke()代替firstStringMethod().

         GetAString firstStringMethod=x.ToString;  //  智能检测,效果是一样的     不能加(),输入圆括号调用 一个方法,返回一个不赋予委托变量的字符串对象。只能把方法的地址赋予委托变量。

 

//类中定义方法
class MathOperations
{
    public static double MultiplyByTwo(double value)
    {
        return double value*2;
    }

    public static double Square(double value)
    {
        returnn double value*value;
    }
}

using System;

//程序命名空间中写程序
namespace MyDelegate
{
    //委托
    delegate double DoubleOp(double value);
    class Program
    {
        static void Main()
               {
                 DoubleOp[] operations={MathOperations.MultiplyByTwo,MathOperations.Square};
                 for(int i=0;i<operations.Length;i++)
                 {
                     Console.WriteLine("Using operations[{0}]",i);

                     ProcessAndDisplayNumber(operations[i],2.0);// 含委托参数的方法
                 }  
               }
    }

    public void ProcessAndDisplayNumber(DoubleOp action,double value)
    {
        DoubleOp result=action(value);
        Console.WriteLine("Value is {0},result of operation is {1}",value,result);
    }


}


        

多播委托

  class Program

{

    static void main()

{

    Action <double>operations=MathOperations.MultiplyByTwo;

    operations+=MathOperations.Square;

    ProcessAndDisplayNumber(operations, 2.0);// 调用这个含委托的方法

}

classs MathOperations

{  public static void MultiplyByTwo(double value)

 {

 double result =value*2;

 Console.WriteLine("Multiply by  2:{0} gives{1}",value ,result);

}

public static void Square

{

   double result=value*value;

   Console.WriteLine("Sqaring :{0} gives {1} ",value,result);

}


//有方法了,现在 就开始使用这个委托

static void ProcessAndDisplayNumber(Action<double> action, double value)

{

     Console.WriteLine();

     Console.WriteLine(" ProcessAndDisplayNumber called with value {0}",value);

      action(value);

}

}


匿名方法

using System;

namespace Program1

{

   class Program


{

  static void Main()

{

 string mid=",middle part,";

 Func<string ,string >anonDel=delegate(string param)

{

    param+=mid;

    param+="and this was added to the string.";

    return param;

};

Console.WriteLine(anonDel(" Start of string"));

}

}

 }

}

从C#3.0开始,可以使用Lambda表达式替代匿名方法。


  

0 0
原创粉丝点击