委托

委托三部曲: 1、声明委托 2、实例化委托 3、委托对象调用方法
简单理解委托就是它给方法的签名和返回类型指定名称。在定义委托的时,必须给出它所表示的方法的签名和返回类型等全部细节。
实际上,定义一个委托就是定义一个新类。委托实现为派生自基类System.MulticastDelegate的类,此类又派生自System.Delegate。例如:

       delegate void student();   //无参的void返回类型
       delegate string student();  //无参的string返回类型
       delegate string student(string name);  //有参的string返回类型

      由上面的例子我们可以知道,委托的定义是很灵活的。接下来我们看看委托例子:

      private delegate string GetString(); //1、声明委托
      static void Main()
      {
        int x=9;
        GetString studentMethod=new GetString (x.ToString);//2、实例化委托
       studentMethod.Invoke();//3、委托调用方法
      }

    在这段代码中,实例化了类型GetString 的一个委托,并对它进行初始化,使它引用整型变量X的ToString()方法。注意委托包含的只是一个或多个方法的地址,所以这里是x.ToString而不是x.ToString()。委托的一个特征是他们的类型是安全的,可以确保被调用的方法的签名是正确的(给委托的实力可以引用任何类型的任何对象上的实例方法或静态方法--只要方法的签名匹配委托的签名即可)

下面举一个委托数组的例子,如下:

class MathOper
{
    public static double MultiplyByTwo(double value)
    {
        return value * 2;
    }
    public static double square(double value)
    {
        return value * value;
    }
}
delegate double DoubleOp(double x);
static void Main()
    {
        DoubleOp[] oper =
        {
            MathOper.MultiplyByTwo,
            MathOper.square
        };
        for (int i = 0; i < oper.Length; i++)
        {
            Console.WriteLine("****************START***************");
            ProcessAndDisplayNumber(oper[i],2.2);
            ProcessAndDisplayNumber(oper[i],5.22);
            ProcessAndDisplayNumber(oper[i], 9.82);
            Console.WriteLine("****************END***************");
        }
        Console.ReadKey();
    }
    static void ProcessAndDisplayNumber(DoubleOp action,double value)
    {
        double result = action(value);
        Console.WriteLine("value is {0},result is {1}",value,result);
    }

在这段代码中,该数组的每个元素都初始化为由MathOper类实现的不同操作。然后遍历这个数组,把每个操作应用到3个不同的值上。这说明了使用委托的一种方式-----把方法组合到一个数组中来使用,这样就可以在循环中调用不同的方法。这段代码的关键一行是
ProcessAndDisplayNumber(oper[i],2.2);
其中传递了委托名,不带任何参数。

除了为每个参数和返回类型定义一个新委托类型之外,还可以使用Acion和Func委托。
泛型Acion委托表示引用一个void返回类型的方法。这个委托类存在不同的变体,可以传递至多16种不同的参数类型。没有泛型参数的Action类可调用没有参数的方法。如:Action<in T1,in T2>
Func委托可以以类似的方式使用。允许调用带返回类型的方法。与Acion类似定义了不同的变体,可以传递至多16种不同的参数类型和一个返回类型。如:Func<in T,out Result>调用带一个参数的方法。
Func<double,double>[] oper={ MathOper.MultiplyByTwo, MathOper.square};//这段代码声明委托类型数组

下面举一个排序的例子:

class BubbleSort
{
static public void Sort<T>(IList<T> sortArray,Func<T,T,bool> comparison)
{
bool swapped = true;
do
{
swapped = false;
for (int i = 0; i < sortArray.Count-1; i++)
{
if(comparison(sortArray[i+1], sortArray[i]))
{
T temp = sortArray[i];
sortArray[i] = sortArray[i+1];
sortArray[i + 1] = temp;
swapped = true;
}
}
} while (swapped);
}
}

在这段代码中,if比较的返回类型是布尔类型。这样就可以很灵活的进行排序,你可以传一串对象数组,通过比较每个对象的属性大小进行排序,如人员的薪酬排序。

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

       Action<double> ac = MathOper.MultiplyByTwo;
        ac += MathOper.square;

其中定义MathOper.MultiplyByTwo和MathOper.squarevoid返回类型。同理从委托中删除方法可以使用”-=“。
多播委托包含一个逐个调用的委托集合,如果其中的一个方法异常,整个迭代就会停止。不过可以使用Delegate类定义的GetInvocationList()方法解决,如:

Action de=one;de+=two;
Delegate[] delegates=de.GetInvocationList();
      foreach(Action d in delegates)
      {
        try
           {
              d();
            }
        catch(Exception)
            {
                Console.WriteLine("Exception");
            }
       
       }

假如在执行one方法的时候抛出异常,整个迭代依然继续,不会停止。

posted @ 2018-11-20 22:43  泽哥的学习笔记  阅读(226)  评论(0编辑  收藏  举报