c#软件开发学习笔记
一、委托概述
1.1 定义与本质
委托(Delegate) 是一种引用类型,用于存储函数(方法)的引用。它就像一个"函数类型"的变量,可以存储、传递和调用方法。
// 定义委托类型
public delegate void MyDelegate();
public delegate int CalculateDelegate(int a, int b);
核心特性:
- 委托是类型安全的函数指针
- 所有委托都派生自
System.Delegate类 - 用于实现事件和回调方法
1.2 委托的作用
| 应用场景 | 说明 |
|---|---|
| 回调机制 | 将方法作为参数传递,实现延迟执行 |
| 事件处理 | GUI编程中处理用户操作(点击、按键等) |
| 策略模式 | 运行时动态选择算法 |
| 异步编程 | 处理异步操作的完成通知 |
二、委托的声明与实例化
2.1 委托声明语法
// 语法格式:访问修饰符 delegate 返回值类型 委托名(参数列表)
public delegate void MyDelegate1(); // 无参数无返回值
public delegate void MyDelegate2(string message); // 带参数无返回值
public delegate int MyDelegate3(int a, int b); // 带参数有返回值
2.2 委托实例化方式
方式一:使用 new 关键字
public delegate int CalculateDelegate(int a, int b);
class Calculator
{
public int Add(int a, int b) => a + b;
public int Subtract(int a, int b) => a - b;
}
// 实例化委托
Calculator calc = new Calculator();
CalculateDelegate addDelegate = new CalculateDelegate(calc.Add);
方式二:直接赋值(简写形式)
CalculateDelegate subDelegate = calc.Subtract; // 编译器自动推断
方式三:使用 Invoke 方法调用
int result = addDelegate.Invoke(10, 20); // 等价于 addDelegate(10, 20)
2.3 完整示例
delegate void MyDel(int v1, string v2);
delegate int Number(int v1, int v2);
class Program
{
static void Main()
{
Number addDelegate = new Number(Add);
Console.WriteLine(addDelegate(10, 10)); // 输出:20
// 简写形式
Number subDelegate = Sub;
Console.WriteLine(subDelegate(200, 10)); // 输出:190
}
static int Add(int a, int b) => a + b;
static int Sub(int a, int b) => a - b;
}
三、多播委托(Multicast Delegate)
3.1 概念
一个委托变量可以存储多个方法,称为多播委托。使用 += 添加方法,使用 -= 移除方法。
3.2 基本操作
delegate void MyDel(string s);
class Program
{
static void Main()
{
// 创建多播委托
MyDel multiDelegate = Fn1;
multiDelegate += Fn2;
multiDelegate += Fn3;
// 调用委托,所有绑定的方法都会执行
multiDelegate("Hello");
// 移除方法
multiDelegate -= Fn2;
// 再次调用,只执行 Fn1 和 Fn3
multiDelegate("World");
}
static void Fn1(string s) => Console.WriteLine($"Fn1: {s}");
static void Fn2(string s) => Console.WriteLine($"Fn2: {s}");
static void Fn3(string s) => Console.WriteLine($"Fn3: {s}");
}
3.3 重要注意事项
问题:移除实例方法时的陷阱
// 错误示例:每次 new Test() 创建不同对象
MyDel m = Fn1;
m += new Test().Fn2;
m -= new Test().Fn2; // ❌ 无法移除,因为不是同一个对象引用
// 正确方法1:保存对象引用
MyDel m1 = Fn1;
Test t = new Test();
m1 += t.Fn2;
m1 -= t.Fn2; // ✅ 成功移除
// 正确方法2:使用静态方法
MyDel m2 = Fn1;
m2 += Test.Fn3;
m2 -= Test.Fn3; // ✅ 成功移除
3.4 空委托处理
MyDel myDelegate = null;
// 方法1:条件判断
if (myDelegate != null)
{
myDelegate("Hello");
}
// 方法2:空条件运算符(推荐)
myDelegate?.Invoke("Hello");
四、内置委托
C# 提供了三种常用的内置委托类型,无需手动定义:
4.1 Action 委托
用途:无返回值的方法
| 签名 | 说明 |
|---|---|
Action | 无参数无返回值 |
Action<T> | 1个参数无返回值 |
Action<T1, T2> | 2个参数无返回值 |
Action<T1, T2, ..., T16> | 最多16个参数 |
static void Process(Action<int> action)
{
action?.Invoke(10);
}
// 使用
Process(v => Console.WriteLine($"Value: {v}"));
4.2 Func 委托
用途:有返回值的方法
| 签名 | 说明 |
|---|---|
Func<TResult> | 无参数,返回 TResult |
Func<T, TResult> | 1个参数,返回 TResult |
Func<T1, T2, TResult> | 2个参数,返回 TResult |
Func<T1, ..., T16, TResult> | 最多16个参数 |
static void Calculate(Func<int, int, int> calculator)
{
int result = calculator(10, 20);
Console.WriteLine($"Result: {result}");
}
// 使用
Calculate((a, b) => a + b); // 输出:30
4.3 Predicate 委托
用途:返回布尔值的判断方法
static int FindFirst(int[] arr, Predicate<int> condition)
{
foreach (int item in arr)
{
if (condition(item))
return item;
}
return -1;
}
// 使用
int[] numbers = { 1, 3, 5, 7, 9 };
int even = FindFirst(numbers, v => v % 2 == 0);
4.4 选择建议
| 场景 | 推荐委托 |
|---|---|
| 无返回值 | Action |
| 有返回值 | Func |
| 条件判断 | Predicate 或 Func<T, bool> |
五、泛型委托
5.1 定义泛型委托
// 泛型委托类型
public delegate bool CallBack<T>(T value);
5.2 泛型委托的优势
- 类型安全:编译时检查类型匹配
- 代码复用:一套代码处理多种类型
- 性能优化:避免装箱拆箱
5.3 完整示例:泛型查找方法
// 泛型委托
public delegate bool CallBack<T>(T v);
class MyArray
{
// 泛型查找方法
public static T Find<T>(T[] arr, CallBack<T> callback)
{
for (int i = 0; i < arr.Length; i++)
{
if (callback(arr[i]))
{
return arr[i];
}
}
return default(T); // 返回类型默认值
}
}
// 使用示例
class Program
{
static void Main()
{
int[] numbers = { 1, 23, 32, 21 };
Console.WriteLine(MyArray.Find(numbers, v => v % 2 == 0)); // 输出:32
string[] names = { "吴亦凡", "罗志祥", "李云迪" };
Console.WriteLine(MyArray.Find(names, v => v.StartsWith("罗"))); // 输出:罗志祥
}
}
六、Lambda 表达式
6.1 概念
Lambda 表达式是一种匿名函数,提供简洁的语法来创建委托实例。
6.2 语法格式
// 完整语法
(参数列表) => { 函数体 }
// 简写形式
(参数) => 表达式 // 单个表达式可省略 {} 和 return
6.3 简写规则
| 规则 | 示例 |
|---|---|
| 省略参数类型 | (a, b) => a + b |
| 单参数省略括号 | a => a * 2 |
| 单表达式省略花括号 | a => a * 2 |
6.4 实际应用
int[] numbers = { 19, 19, 20, 3, 18 };
// 使用 Lambda 作为参数
int firstEven = Array.Find(numbers, v => v % 2 == 0); // 输出:20
// 复杂条件
string[] names = { "吴亦凡", "罗志祥", "郑爽" };
string result = Array.Find(names, v => v.EndsWith("祥") && v.Length == 3);
1031



被折叠的 条评论
为什么被折叠?



