C# - 委托
如果我们想将函数作为参数传递怎么办?C# 如何处理回调函数或事件处理程序?答案是 - 委托。
委托是一种引用类型数据类型,它定义了方法签名。您可以像其他数据类型一样定义委托变量,这些变量可以引用与委托具有相同签名的任何方法。
使用委托涉及三个步骤
- 声明委托
- 创建实例并引用方法
- 调用委托
委托可以使用 delegate
关键字后跟函数签名来声明,如下所示。
委托语法
[access modifier] delegate [return type] [delegate name]([parameters])
以下声明了一个名为 MyDelegate
的委托。
示例:声明委托
public delegate void MyDelegate(string msg);
上面,我们声明了一个名为 MyDelegate
的委托,它具有一个
声明委托后,我们需要设置目标方法或 lambda 表达式。我们可以通过使用 new 关键字创建委托对象并传入签名与委托签名匹配的方法来完成。
示例:设置委托目标
public delegate void MyDelegate(string msg); // declare a delegate
// set target method
MyDelegate del = new MyDelegate(MethodA);
// or
MyDelegate del = MethodA;
// or set lambda expression
MyDelegate del = (string msg) => Console.WriteLine(msg);
// target method
static void MethodA(string message)
{
Console.WriteLine(message);
}
您可以通过直接赋值方法来设置目标方法,而无需创建委托对象,例如:MyDelegate del = MethodA
。
设置目标方法后,可以使用 Invoke()
方法或 ()
运算符调用委托。
示例:调用委托
del.Invoke("Hello World!");
// or
del("Hello World!");
以下是一个完整的委托示例。
示例:委托
public delegate void MyDelegate(string msg); //declaring a delegate
class Program
{
static void Main(string[] args)
{
MyDelegate del = ClassA.MethodA;
del("Hello World");
del = ClassB.MethodB;
del("Hello World");
del = (string msg) => Console.WriteLine("Called lambda expression: " + msg);
del("Hello World");
}
}
class ClassA
{
static void MethodA(string message)
{
Console.WriteLine("Called ClassA.MethodA() with parameter: " + message);
}
}
class ClassB
{
static void MethodB(string message)
{
Console.WriteLine("Called ClassB.MethodB() with parameter: " + message);
}
}
下图说明了委托。

将委托作为参数传递
方法可以具有委托类型的参数,如下所示。
示例:委托
public delegate void MyDelegate(string msg); //declaring a delegate
class Program
{
static void Main(string[] args)
{
MyDelegate del = ClassA.MethodA;
InvokeDelegate(del);
del = ClassB.MethodB;
InvokeDelegate(del);
del = (string msg) => Console.WriteLine("Called lambda expression: " + msg);
InvokeDelegate(del);
}
static void InvokeDelegate(MyDelegate del) // MyDelegate type parameter
{
del("Hello World");
}
}
class ClassA
{
static void MethodA(string message)
{
Console.WriteLine("Called ClassA.MethodA() with parameter: " + message);
}
}
class ClassB
{
static void MethodB(string message)
{
Console.WriteLine("Called ClassB.MethodB() with parameter: " + message);
}
}
注意
在 .NET 中,Func 和 Action 类型是内置的泛型委托,大多数常用委托都应该使用它们,而不是创建新的自定义委托。
多播委托
委托可以指向多个方法。指向多个方法的委托称为多播委托。“+”或“+=”运算符将函数添加到调用列表,而“-”和“-=”运算符将其删除。
示例:多播委托
public delegate void MyDelegate(string msg); //declaring a delegate
class Program
{
static void Main(string[] args)
{
MyDelegate del1 = ClassA.MethodA;
MyDelegate del2 = ClassB.MethodB;
MyDelegate del = del1 + del2; // combines del1 + del2
del("Hello World");
MyDelegate del3 = (string msg) => Console.WriteLine("Called lambda expression: " + msg);
del += del3; // combines del1 + del2 + del3
del("Hello World");
del = del - del2; // removes del2
del("Hello World");
del -= del1 // removes del1
del("Hello World");
}
}
class ClassA
{
static void MethodA(string message)
{
Console.WriteLine("Called ClassA.MethodA() with parameter: " + message);
}
}
class ClassB
{
static void MethodB(string message)
{
Console.WriteLine("Called ClassB.MethodB() with parameter: " + message);
}
}
加法和减法运算符始终作为赋值的一部分工作:del1 += del2;
完全等同于 del1 = del1+del2;
,减法同理。
如果委托返回一个值,则当调用多播委托时,将返回最后分配的目标方法的值。
示例:返回值的多播委托
public delegate int MyDelegate(); //declaring a delegate
class Program
{
static void Main(string[] args)
{
MyDelegate del1 = ClassA.MethodA;
MyDelegate del2 = ClassB.MethodB;
MyDelegate del = del1 + del2;
Console.WriteLine(del());// returns 200
}
}
class ClassA
{
static int MethodA()
{
return 100;
}
}
class ClassB
{
static int MethodB()
{
return 200;
}
}
泛型委托
泛型委托的定义方式与委托相同,但使用泛型类型参数或返回类型。设置目标方法时必须指定泛型类型。
例如,考虑以下用于 int 和 string 参数的泛型委托。
示例:泛型委托
public delegate T add<T>(T param1, T param2); // generic delegate
class Program
{
static void Main(string[] args)
{
add<int> sum = Sum;
Console.WriteLine(sum(10, 20));
add<string> con = Concat;
Console.WriteLine(conct("Hello ","World!!"));
}
public static int Sum(int val1, int val2)
{
return val1 + val2;
}
public static string Concat(string str1, string str2)
{
return str1 + str2;
}
}
委托也用于声明事件和匿名方法。
在此处了解有关委托的更多信息。
要记住的要点
- 委托是定义签名的引用类型数据类型。
- 委托类型变量可以引用与委托具有相同签名的任何方法。
- 语法:[访问修饰符] delegate [返回类型] [委托名称]([参数])
- 目标方法的签名必须与委托签名匹配。
- 委托可以像普通函数或 Invoke() 方法一样调用。
- 可以使用“+”或“+=”运算符将多个方法分配给委托,并使用“-”或“-=”运算符删除。这称为多播委托。
- 如果多播委托返回一个值,则它返回最后分配的目标方法的值。
- 委托用于在 C# 中声明事件和匿名方法。