初面网初面网

委托

概念与理解

类似于C++中的函数指针,委托是对方法的引用(所以其是一种引用类型变量),常用于实现事件和回调方法,并均派生自System.Delegate类。

先看一个例子:

using System;

delegate int NumberChanger(int n);
namespace DelegateAppl
{
  class TestDelegate
  {
    static int num = 10;
    public static int AddNum(int p)
    {
        num += p;
        return num;
    }

    public static int MultNum(int q)
    {
        num *= q;
        return num;
    }
    public static int getNum()
    {
        return num;
    }

    static void Main(string[] args)
    {
        // 创建委托实例
        NumberChanger nc1 = new NumberChanger(AddNum);
        NumberChanger nc2 = new NumberChanger(MultNum);
        // 使用委托对象调用方法
        nc1(25);
        Console.WriteLine("Value of Num: {0}", getNum());
        nc2(5);
        Console.WriteLine("Value of Num: {0}", getNum());
        Console.ReadKey();
    }
  }
}

直接看Main里的实例与调用,看到 NumberChanger 被实例化为nc1和nc2,此时AddNum和MultNum在 NumberChanger 中。然后通过实例化的nc1和nc2进行调用,达到一般函数调用一样的效果。

所以感觉上,委托像是伪装了的一层函数,通过伪装,代行函数的职能。“委托”这个翻译也很到位,就是一个函数的功能被委托给了委托类型的变量。

多播(组播)

一个委托调用了多个方法,这种委托称为多播委托。

public class App
{
  delegate int DNumChange(int a, int b);
  
  static int numAdd(int a, int b)
  {
    Console.WriteLine("Add: {0}", a + b);
    return a + b;
  }

  static int numMinus(int a, int b)
  {
    Console.WriteLine("Minus: {0}", a - b);
    return a - b;
  }

  static void Main(string[] args)
  {
    DNumChange nc = numAdd;
    nc += numMinus;         // 委托中添加方法
    // nc -= numAdd;        // 委托中去掉方法
    nc(3,2);

    Console.ReadKey();
  }
}

委托如果不指向任何方法会报错,所以使用前要判断一下。关键词:GetInvocationList

Delegate[] delegates = nc.GetInvocationList();

下面是通过遍历的方式去调用委托中的方法:

public class App
{
  delegate int DNumChange(int a, int b);
  
  static int numAdd(int a, int b)
  {
    Console.WriteLine("Add: {0}", a + b);
    return a + b;
  }

  static int numMinus(int a, int b)
  {
    Console.WriteLine("Minus: {0}", a - b);
    return a - b;
  }

  static void Main(string[] args)
  {
    DNumChange nc = numAdd;
    nc += numMinus;

    Delegate[] delegates= nc.GetInvocationList();

    foreach (Delegate d in delegates) 
    { 
        d.DynamicInvoke(3,2);   // 不要忘记写参数
    }

    Console.ReadKey();
  }
}

Action委托

为了方便开发,系统预定义了两种委托类型:Action委托和Func委托。

Action可以指向没有返回值、没有参数的方法。

public class App
{
  static void printHello()
  {
    Console.WriteLine("Hello!");
  }

  static void Main(string[] args)
  {
    Action a = printHello;

    a();

    Console.ReadKey();
  }
}

Func委托

Func委托可以指向有返回值的方法。

public class App
{
  static int printRes()
  {
    Console.WriteLine("Hello!");
    return -1;
  }

  static void Main(string[] args)
  {
    Func<int> a = printRes;

    a();

    Console.ReadKey();
  }
}

匿名方法

public class App
{
  static void Main(string[] args)
  {
    // 使用Func去创建一个函数类型。最后一个泛型是返回值的类型
    // 使用delegate去委托一个方法
    Func<int, int, int> plus = delegate(int x, int y) { return x + y; };

    Console.WriteLine(plus(1,2));

    Console.ReadKey();
  }
}

更新于 2025/2/26