解释C#中委托的概念

如果您是 C 程序员,那么可以将委托视为指向函数的指针。然而,C# 中的委托不仅仅是一个简单的函数指针。本文解释了委托的概念及其在日常编程中的用途。

本质上,委托提供了一定程度的间接性。它们封装了一段代码,可以以类型安全的方式传递和执行。它不是立即执行行为,而是包含在一个对象中。您可以对该对象执行多种操作,其中之一是执行包含的行为。

使用委托允许我们编写高阶函数,即可以接收函数作为参数或返回函数作为返回值的函数。委托类型定义委托可以表示的方法签名,特别是方法的返回类型及其参数类型。在以下示例中,Transformer 是一个委托,可以表示任何接受并返回整数的方法。

delegate int Transformer(int x);

我们可以将任何方法(包括 lambda、实例或静态方法)分配给满足签名的 Transformer 实例。例如 -

Transformer square = x => x * x;
Transformer cube = x => x * x * x;

Console.WriteLine(square(3)); // 打印 9
Console.WriteLine(cube(5)); // prints 125

什么时候使用委托?

当想要执行某些动作的代码不知道这些动作应该是什么的细节但知道这些动作的接口时,通常会使用委托。

在编程中,我们经常面临需要执行特定动作的情况,但我们事先不知道要调用哪个方法来执行它。委托通过用委托替换该行为,然后根据上下文和情况的需要传递具有适当行为的该委托的具体实例来帮助我们解决这个问题。

为了让代表做任何事情,需要发生四件事 -

1) 需要声明委托类型。

委托类型本质上是它所表示的函数的定义,即它由函数将接受的参数类型和它返回的返回类型组成。

例如,代表一个接受两个数字作为输入并返回一个数字的方法的委托类型可以声明为 -

delegate int Processor(int numOne, int numTwo);

Processor 是一种类型,类似于类创建的类型。要创建这种类型的实例,您需要一个将两个数字作为输入并返回一个布尔值的方法。

2) 要执行的代码必须包含在方法中。

定义一个与上述委托类型具有完全相同签名的方法,并根据运行时的情况执行您想要的操作。例如,以下任何方法都可用于创建 Processor 的实例,因为它们都接受两个数字并返回一个数字。

static int Add(int numOne, int numTwo){
   Return numOne + numTwo;
}
static int Subtract(int numOne, int numTwo){
   Return numOne - numTwo;
}

3) 必须创建一个委托实例。

现在您有了一个委托类型和一个具有正确签名的方法,您可以创建该委托类型的一个实例。在这样做时,我们实际上是在告诉 C# 编译器在调用委托实例时执行此方法。

Processor processorOne = new Processor(Add);
Processor processorTwo = new Processor(Subtract);

上面的例子假设 Add 和 Subtract 方法是在我们创建委托实例的同一个类中定义的。如果方法在不同的类中定义,我们将需要该类的实例。

4) 必须调用委托实例。

这只是在委托实例上调用一个方法的问题,该方法被命名为 Invoke,这并不奇怪。委托实例上的此方法具有与委托类型声明指定的参数和返回类型相同的列表。调用 Invoke 将执行委托实例的操作。

int sum = processorOne.Invoke(3, 5);

但是,C# 使它变得更加容易。您可以直接调用委托实例,就好像它本身就是一个方法一样。例如,

int difference = processorTwo(10, 6);

合并和删除委托

如果我们想通过一次委托实例调用来执行一系列不同的操作,C# 允许我们这样做。系统。委托类型有两个静态方法,称为Combine 和Remove。

1.组合

创建一个具有调用列表的新委托,该调用列表连接作为参数传递的委托的调用列表。当新的委托实例被调用时,它的所有动作都按顺序执行。

public static Delegate Combine(params Delegate[] delegates); // OR
public static Delegate Combine(Delegate a, Delegate b);

如果调用列表中的任何操作引发异常,则会阻止执行任何后续操作。

2. 删除

从另一个委托的调用列表中删除最后一次出现的委托调用列表。返回一个具有调用列表的新委托,该调用列表通过获取源的调用列表并删除值调用列表的最后一次出现而形成。

public static Delegate Remove(Delegate source, Delegate value);

概括

  • 委托使用特定类型和一组参数封装行为,类似于单方法接口。

  • 委托类型声明所描述的类型签名决定了可以使用哪些方法来创建委托实例和调用签名。

  • 创建委托实例需要一个我们希望在调用委托时执行的方法。

  • 委托实例是不可变的,类似于字符串。

  • 每个委托实例都包含一个调用列表——一个动作列表。

  • 委托实例可以相互组合和删除。

示例

using System;
class Program{
   delegate int Transformer(int x);
   delegate int Processor(int numOne, int numTwo);
   static void Main(){
      Transformer square = x => x * x;
      Transformer cube = x => x * x * x;
      Console.WriteLine(square(3)); // 打印 9
      Console.WriteLine(cube(5)); // prints 125
      Processor processorOne = new Processor(Add);
      Processor processorTwo = new Processor(Subtract);
      int sum = processorOne.Invoke(3, 5);
      Console.WriteLine(sum); // prints 8
      int difference = processorTwo(10, 6);
      Console.WriteLine(difference); // prints 4
   }
   static int Add(int numOne, int numTwo){
      return numOne + numTwo;
   }
   static int Subtract(int numOne, int numTwo){
      return numOne - numTwo;
   }
}
输出结果
9
125
8
4