解释 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)); // 打印 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 processOne = new Processor(Add); Processor processTwo = new Processor(Subtract);
上述示例假设 Add 和 Subtract 方法在我们创建委托实例的同一类中定义。如果方法定义在不同的类中,我们将需要该类的实例。
4) 必须调用委托实例。
这只是在委托实例上调用方法的问题,该方法名为 Invoke,这并不奇怪。委托实例上的此方法具有委托类型声明指定的相同参数列表和返回类型。调用 Invoke 将执行委托实例的操作。
int sum =processorOne.Invoke(3, 5);
但是,C# 使它变得更加简单。您可以直接调用委托实例,就好像它本身就是一个方法一样。例如,
int difference =processorTwo(10, 6);
合并和删除委托
如果我们想通过一次委托实例调用来执行一系列不同的操作,C# 允许我们这样做。System.Delegate 类型有两个静态方法,称为 Combine 和 Remove。
1. Combine
创建一个新的委托,其中包含一个调用列表,该列表将作为参数传递的委托的调用列表连接起来。当调用新的委托实例时,其所有操作都会按顺序执行。
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)); // prints 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