一、什么是委托
1.1 官方解释
委托是一种定义方法签名的类型。当实例化委托时,您可以将其实例与任何具有兼容签名的方法相关联,并通过委托实例调用该方法。
1.2 个人理解
委托就是用于封装和执行方法(函数)的一个类。
★事件是一种特殊的委托。
二、如何声明委托
C# 中有四种常见的委托声明方式:
2.1delegate(自定义委托)
public delegate int TestDelegate(int x, int y);可以无返回值,也可以指定返回值类型。
支持0 到 32 个参数。
2.2Action(无返回值泛型委托)
无返回值(即返回
void)。支持0 到 16 个参数。
示例:
Action:无参,无返回值。Action<int, string>:接收int和string参数,无返回值。Action<int, string, bool>:三个参数,无返回值。Action<int, int, int, int>:四个int参数,无返回值。
2.3Func(有返回值泛型委托)
必须有返回值(不能为
void)。支持0 到 16 个输入参数,最后一个泛型参数为返回类型。
示例:
Func<int>:无参,返回int。Func<object, string, int>:接收object和string,返回int。Func<T1, T2, T3, int>:三个泛型输入参数,返回int。
2.4Predicate(布尔返回值泛型委托)
仅接受一个参数。
**返回值固定为
bool**。
示例:
Predicate<int>:接收int,返回bool。定义形式:
public delegate bool Predicate<T>(T obj);
2.5 四者之间的区别总结
委托类型 | 参数数量范围 | 返回值要求 |
|---|---|---|
delegate | 0 ~ 32 | 可无返回值,也可指定类型 |
Action | 0 ~ 16 | 无返回值( |
Func | 0 ~ 16(+1 返回值) | 必须有返回值 |
Predicate | 仅 1 个 | 返回值固定为 |
★注:部分资料中提到 Action/Func 最多支持 4 个参数,这是早期 .NET 版本限制;现代 C#(.NET Framework 4.0+ / .NET Core)已支持最多16 个参数。
三、委托的使用示例
3.1delegate的使用
public delegate int MethodDelegate(int x, int y); private static MethodDelegate method; static void Main(string[] args) { method = new MethodDelegate(Add); Console.WriteLine(method(10, 20)); // 输出:30 Console.ReadKey(); } private static int Add(int x, int y) => x + y;3.2Action的使用
static void Main(string[] args) { Test<string>(Action, "Hello World!"); Test<int>(Action, 1000); Test<string>(p => Console.WriteLine("{0}", p), "Lambda Hello"); Console.ReadKey(); } public static void Test<T>(Action<T> action, T p) => action(p); private static void Action(string s) => Console.WriteLine(s); private static void Action(int s) => Console.WriteLine(s);★
Action常用于执行操作,无需返回结果。
3.3Func的使用
static void Main(string[] args) { Console.WriteLine(Test<int, int>(Fun, 100, 200)); // 输出:300 Console.ReadKey(); } public static int Test<T1, T2>(Func<T1, T2, int> func, T1 a, T2 b) => func(a, b); private static int Fun(int a, int b) => a + b;★
Func常用于需要返回计算结果的场景。
3.4Predicate的使用
static void Main(string[] args) { Point[] points = { new Point(100, 200), new Point(150, 250), new Point(250, 375), new Point(275, 395), new Point(295, 450) }; Point first = Array.Find(points, ProductGT10); Console.WriteLine("Found: X = {0}, Y = {1}", first.X, first.Y); Console.ReadKey(); } private static bool ProductGT10(Point p) => p.X * p.Y > 100000;★
Predicate常用于集合筛选(如Array.Find,List.FindAll等)。
四、委托的清空
4.1 方法一:循环移除
public MethodDelegate OnDelegate; public void ClearDelegate() { while (OnDelegate != null) { OnDelegate -= OnDelegate; } }★⚠️ 注意:此写法在多线程环境下可能不安全,且逻辑上存在争议(每次减去自身可能导致未完全清除)。更推荐方法二。
4.2 方法二:使用GetInvocationList
public MethodDelegate OnDelegate; static void Main(string[] args) { Program test = new Program(); if (test.OnDelegate != null) { Delegate[] dels = test.OnDelegate.GetInvocationList(); foreach (var del in dels) { test.OnDelegate -= (MethodDelegate)del; } } }★此方法安全可靠,适用于多播委托的彻底清空。
五、委托的特点
类似于 C++ 的函数指针,但类型安全。
允许将方法作为参数传递。
可用于实现回调机制。
支持多播(多个方法绑定到同一个委托,依次调用)。
方法签名不必完全一致(协变/逆变支持)。
六、总结
类型 | 参数数量 | 返回值 | 典型用途 |
|---|---|---|---|
delegate | 0–32 | 任意或无 | 自定义委托 |
Action | 0–16 | 无( | 执行操作 |
Func | 0–16 | 必须有 | 计算并返回结果 |
Predicate | 1 | bool | 条件判断、筛选 |
参考资料:
http://www.fengfly.com/plus/view-209140-1.html
http://www.cnblogs.com/foolishfox/archive/2010/09/16/1827964.html
https://www.cnblogs.com/akwwl/p/3232679.html
https://www.cnblogs.com/xiao-qian/p/12688043.html
- EOF -
技术群:添加小编微信dotnet999
公众号:dotnet讲堂