C#委托用法详解(附带实例)
C# 的委托是一种对方法的引用,类似于 C/C++ 的函数指针(function pointer),但是 C# 的委托与 C 的不同在于其面向对象,安全性较佳。所谓的委托从程序设计端的观点来看,就是将一个方法(method)或函数当作参数,传递给另一个方法。
简单地说,就是一个方法的参数是方法。
过去我们设计方法时,所传递的参数有 int、double、string 等对象。如果设计的方法比较复杂,就会传递多个不同类型的参数,这时在方法内会有 if 的条件判断语句,然后在不同的 if 条件区块内完成这些参数的工作。
上述 [存取修饰词] 是可选项,其他是必需的,下列是声明委托 NumOperation() 的实例:
有的程序设计师会分段撰写,先创建委托对象,再绑定方法实例化,如下:
【实例 1】简单委托的实例,笔者分别使用完整与简化声明委托目标对象,同时调用时也使用 Invoke() 和简化 () 方法。
读者可以留意第 11 行和第 12 行创建委托目标对象的方法:
【实例 2】重新设计实例 1 先声明委托对象,再绑定方法的写法。
【实例 3】使用 MyDelegate 类创建方法,然后让顶级语句设定委托对象目标方法,再予以调用,这个程序多设计了回传静态变量的方法。
【实例 4】将委托指向其他方法。
程序第 5 行将委托指向 SampleMethod 类的静态方法 StaticMethod(),程序第 6 行执行委托 obj(),可以得到第 2 行的输出。
【实例 5】委托当作方法的参数。
【实例 6】使用两个委托,然后用“+”创建多播委托,然后用“-”移除多播委托中的一个委托,分别调用这些委托同时观察执行结果。
【实例 7】声明泛型委托,然后分别使用 int 和 string 数据类型实体化此泛型委托对象。
简单地说,就是一个方法的参数是方法。
过去我们设计方法时,所传递的参数有 int、double、string 等对象。如果设计的方法比较复杂,就会传递多个不同类型的参数,这时在方法内会有 if 的条件判断语句,然后在不同的 if 条件区块内完成这些参数的工作。
C#委托操作
委托操作有 4 个步骤:- 声明委托,这是类型声明,所以顶级语句必须在此委托声明前面;
- 设计目标方法;
- 创建委托对象实例并将此实例绑定目标方法,也可以说是引用方法(reference the method);
- 调用(invoke)委托。
1) 声明委托
声明委托的关键词是 delegate,语法如下:[存取修饰词] delegate 数据类型 委托名称(系列参数);
上述 [存取修饰词] 是可选项,其他是必需的,下列是声明委托 NumOperation() 的实例:
public delegate int NumOperation(int x, int y);注意,委托声明必须在顶级语句后面,在顶级语句设计中来说委托一般都放在程序后方,但是在类声明之前。
2) 设计目标方法
可以创建目标方法,下列是实例:
public static int Add(int a, int b)
{
return a + b;
}
public static int Sub(int a, int b)
{
return a - b;
}
所设计的目标方法与委托必须符合下列条件:
- 有相同的数据类型,此例中 NumOperation() 委托数据类型是 int,Add() 和 Sub() 数据类型也都是 int;
- 目标方法与委托声明有相同的方法签名,也就是参数数目与类型需要相同。Add() 和 Sub() 方法所传递的参数都是 (int, int),这也和 NumOperation() 相同。
3) 创建委托对象实例并设定目标方法的常见用法
我们可以使用 new 关键词创建委托对象,设定目标方法,例如,前面我们创建了两个目标方法,当我们创建委托对象时需要设定此对象的方法,下列是实例:NumOperation opAdd = new NumOpertion(Add); NumOperation opSub = new NumOpertion(Sub);上述 opAdd 的目标方法是 Add,opSub 的目标方法是 Sub。当委托对象 opAdd 经过委托设定目标是 Add 方法后,这个 opAdd 对象就有和 Add 方法相同的能力。
4) 创建委托对象实例并设定目标方法的简化用法
还可以将创建委托对象实例简化如下:NumOperation opAdd = Add; NumOperation opSub = Sub;
有的程序设计师会分段撰写,先创建委托对象,再绑定方法实例化,如下:
NumOperation opAdd, opSub; opAdd = Add; opSub = Sub;
5) 调用委托
可以使用 Invoke() 或是直接使用 () 调用委托,下列是实例:opAdd.Invoke(5, 2);或是:
opAdd(5, 2);
6) 简单的委托实例
因为顶级语句必须在类型声明前方,所以委托是在程序下方声明。【实例 1】简单委托的实例,笔者分别使用完整与简化声明委托目标对象,同时调用时也使用 Invoke() 和简化 () 方法。
static int Add(int a, int b)
{
return a + b;
}
static int Sub(int a, int b)
{
return a - b;
}
NumOperation opAdd = new NumOperation(Add); // 创建对象与目标是 Add
NumOperation opSub = Sub; // 创建对象与目标是 Sub
// 使用委托对象调用方法
Console.WriteLine($"Delegate Add 结果:{opAdd.Invoke(5, 2)}");
Console.WriteLine($"Delegate Sub 结果:{opSub(5, 2)}");
delegate int NumOperation(int x, int y); // 声明委托
执行结果为:
Delegate Add 结果: 7
Delegate Sub 结果: 3
读者可以留意第 11 行和第 12 行创建委托目标对象的方法:
- 第 11 行 Add 方法是委托 NumOperation() 的参数;
- 第 12 行是简化写法,Sub 方法是委托 NumOpertion() 的参数;
- 另外第 15 行和第 16 行也使用两种方式传递参数调用委托。
【实例 2】重新设计实例 1 先声明委托对象,再绑定方法的写法。
static int Add(int a, int b)
{
return a + b;
}
static int Sub(int a, int b)
{
return a - b;
}
NumOperation opAdd, opSub; // 创建委托对象 opAdd 和 opSub
opAdd = Add; // 设置 opAdd 委托目标方法是 Add
opSub = Sub; // 设置 opSub 委托目标方法是 Sub
// 使用委托对象调用方法
Console.WriteLine($"Delegate Add 结果:{opAdd.Invoke(5, 2)}");
Console.WriteLine($"Delegate Sub 结果:{opSub(5, 2)}");
delegate int NumOperation(int x, int y); // 声明委托
执行结果与实例 1 相同。上个程序的重点是第 11~13 行,在面向对象的概念中,委托的目标方法大多在类内声明,详情可以参考下列实例。【实例 3】使用 MyDelegate 类创建方法,然后让顶级语句设定委托对象目标方法,再予以调用,这个程序多设计了回传静态变量的方法。
NumOperation opAdd = MyDelegate.Add; // 创建对象与目标是 Add
NumOperation opSub = MyDelegate.Sub; // 创建对象与目标是 Sub
// 使用委托对象调用方法
opAdd(5, 2);
Console.WriteLine($"Delegate Add 结果 {MyDelegate.getNum()}");
opSub(5, 2);
Console.WriteLine($"Delegate Sub 结果 {MyDelegate.getNum()}");
delegate int NumOperation(int x, int y); // 声明委托
public class MyDelegate
{
static int result = 0; // 静态变量
public static int Add(int a, int b) // 加法
{
result = a + b;
return result;
}
public static int Sub(int a, int b) // 减法
{
result = a - b;
return result;
}
public static int getNum() // 回传静态变量
{
return result;
}
}
执行结果与实例 1 相同。7) 调整委托指向
当委托声明后同时会绑定此委托的目标,也就是将委托目标封装在对象内,但是程序执行过程我们仍是可以将委托指向其他目标方法。【实例 4】将委托指向其他方法。
SampleMethod sm = new SampleMethod(); // 创建类 SampleMethod 对象
MyDelegate obj = sm.InstanceMethod; // 目标是 InstanceMethod 方法的委托
obj(); // 执行 obj()
obj = SampleMethod.StaticMethod; // 将委托指向 StaticMethod 方法
obj(); // 执行 obj()
delegate void MyDelegate(); // 声明委托
public class SampleMethod
{
public void InstanceMethod()
{
Console.WriteLine("我是 InstanceMethod 方法");
}
public static void StaticMethod()
{
Console.WriteLine("我是 StaticMethod 方法");
}
}
执行结果为:
我是 InstanceMethod 方法
我是 StaticMethod 方法
程序第 5 行将委托指向 SampleMethod 类的静态方法 StaticMethod(),程序第 6 行执行委托 obj(),可以得到第 2 行的输出。
C#委托当作方法的参数
委托也可以被当作方法的参数,详情可以参考下列实例。【实例 5】委托当作方法的参数。
static void InvokeDelegate(MyDelegate delegateObj)
{
delegateObj("认识 C# delegate 委托对象当作方法的参数");
}
MyDelegate objA = JobA.MethodA; // 创建委托当作与目标
InvokeDelegate(objA); // 调用 InvokeDelegate() 方法
MyDelegate objB = JobB.MethodB; // 创建委托当作与目标
InvokeDelegate(objB); // 调用 InvokeDelegate() 方法
public delegate void MyDelegate(string message); // 声明委托
public class JobA // 类 JobA
{
public static void MethodA(string msg)
{
Console.WriteLine($"调用 MethodA :{msg}");
}
}
public class JobB // 类 JobB
{
public static void MethodB(string msg)
{
Console.WriteLine($"调用 MethodB :{msg}");
}
}
执行结果为:
调用 MethodA :认识 C# delegate 委托对象当作方法的参数
调用 MethodB :认识 C# delegate 委托对象当作方法的参数
C#多播委托
委托可以指向多个方法,这个概念称为多播委托(multicast delegate),在这个概念下可以用“+”或是“+=”将方法加到调用列表中,使用“-”或是“-=”则是将特定方法删除。【实例 6】使用两个委托,然后用“+”创建多播委托,然后用“-”移除多播委托中的一个委托,分别调用这些委托同时观察执行结果。
MultiDelegate hiDel, byeDel, multiDel, subHiDel;
hiDel = Greeting.Hi; // 设置委托 hiDel 的引用方法为 Hi
byeDel = Greeting.Goodbye; // 设置委托 byeDel 的引用方法为 Goodbye
// 两个委托相加,创建多播委托(Multicast Delegate)
multiDel = hiDel + byeDel;
// 从多播委托(Multicast Delegate)中移除 hiDel 委托
subHiDel = multiDel - hiDel;
Console.WriteLine("启动 delegate hiDel:");
hiDel("Person A");
Console.WriteLine("启动 delegate byeDel:");
byeDel("Person B");
Console.WriteLine("启动 delegate multiDel:");
multiDel("Person C");
Console.WriteLine("启动 delegate subHiDel:");
subHiDel("Person D");
delegate void MultiDelegate(string s); // 声明委托
public class Greeting
{
// Define two methods that have the same signature as CustomDel.
public static void Hi(string name) // 定义 Hi() 方法
{
Console.WriteLine($" 早安, {name}!");
}
public static void Goodbye(string name) // 定义 Goodbye() 方法
{
Console.WriteLine($" 再见, {name}!");
}
}
执行结果为:
启动 delegate hiDel:
早安, Person A!
启动 delegate byeDel:
再见, Person B!
启动 delegate multiDel:
早安, Person C!
再见, Person C!
启动 delegate subHiDel:
再见, Person D!
C#泛型委托
在 C# 程序中,也可以将泛型应用到委托中,定义泛型委托(generic delegate),这时设定委托对象的目标方法时需指定数据类型。【实例 7】声明泛型委托,然后分别使用 int 和 string 数据类型实体化此泛型委托对象。
Add<int> sum = MyAdd.Sum; // 声明泛型委托对象和目标方法
Console.WriteLine(sum(3, 6));
Add<string> cat = MyAdd.Concat; // 声明泛型委托对象和目标方法
Console.WriteLine(cat("C# ", "是面向对象程序语言"));
public delegate T Add<T>(T x, T y); // 声明泛型委托 Add
public class MyAdd
{
// 参数是 int
public static int Sum(int a, int b)
{
return a + b;
}
// 参数是 string
public static string Concat(string str1, string str2)
{
return str1 + str2;
}
}
执行结果为:
9
C# 是面向对象程序语言
ICP备案:
公安联网备案: