总目录
前言
在C#中,委托(Delegate) 是一种类型安全的函数指针机制,它允许我们将方法作为参数传递给其他方法,或者将方法存储在变量中。委托在 C# 中有广泛的应用,特别是在事件处理、异步编程和回调机制中。本文将详细介绍 C# 中委托的定义、使用方法、高级特性以及最佳实践。
一、什么是委托
1. 定义
- 委托是一种引用类型,表示对具有特定参数列表和返回类型的方法的引用。
- 委托是一种特殊的类,它封装了一个或多个具有相同签名(返回类型和参数列表)的方法。它允许我们将方法作为参数传递给其他方法,或者将方法存储在变量中。 委托可以看作是方法的“蓝图”,它定义了方法的签名(返回类型和参数列表),但不包含方法体。
- 委托是一种类型安全的函数指针,用于封装对方法的引用。它允许将方法作为参数传递、存储在变量中,或通过多播机制调用多个方法。
2. 特点
- 类型安全:委托的签名(参数列表和返回类型)必须与目标方法签名完全匹配。
- 面向对象:委托本质上是继承自
System.MulticastDelegate
的类,支持多态和反射操作。 - 动态调用:运行时根据条件动态选择要调用的方法。
- 多播能力:支持多个方法的链式调用
- 异步支持:通过
BeginInvoke
/EndInvoke
实现异步调用
3. 委托定义语法
委托是一种引用类型,它指向具有特定参数列表和返回类型的方法。委托的定义语法如下:
public delegate ReturnType DelegateName(Parameters);
ReturnType
:委托方法的返回类型。Parameters
:委托方法的参数列表。DelegateName
:委托的名称。
二、如何使用委托
1. 使用步骤
1)定义委托
- 定义委托的方式类似于定义方法
- 相较于定义方法,定义委托需要使用
delegate
关键字,且没有方法体。
- 相较于定义方法,定义委托需要使用
- 委托本质上也是类,因此可定义的位置与类相同。
- 类可以定义在哪里,委托就可定义在哪里。
public delegate int MathOperationDelegate(int a, int b);
2)实例化委托
可以通过以下几种方式实例化委托:
- new 实例化:通过
new
创建委托实例 - 直接赋值 :直接赋值给某个方法
- 匿名方法 :使用匿名方法
- Lambda 表达式:使用 Lambda 表达式
方式1:new 实例化
// 实例化委托:new 实例化
MathOperationDelegate mathOperation = new MathOperationDelegate(Add);
通过new 创建委托实例,必须传入一个方法作为参数,否则会报错
// 1. 定义委托
public delegate int MathOperationDelegate(int a, int b);class Program
{static void Main(){// 3.实例化委托MathOperationDelegate mathOperation = new MathOperationDelegate(Add);}// 2.定义委托对应的方法// 注意:该方法的签名必须与定义的委托签名保持一致public static int Add(int num1, int num2){return num1 + num2;}
}
方式2:直接赋值
C#2.0 提供一个更简单的给委托创建实例的方式,那就是直接赋值。
// 实例化委托:直接赋值,将Add 方法赋值给定义的委托
MathOperationDelegate mathOperation = Add;
// 1. 定义委托
public delegate int MathOperationDelegate(int a, int b);class Program
{static void Main(){// 3.实例化委托:直接赋值,将Add 方法赋值给定义的委托MathOperationDelegate mathOperation = Add;}// 2.定义委托对应的方法// 注意:该方法的签名必须与定义的委托签名保持一致public static int Add(int num1, int num2){return num1 + num2;}
}
方式3:匿名方法
从C# 2.0开始,可以使用匿名方法来创建委托实例。匿名方法是在创建委托实例时定义的方法体,不需要单独命名。
// 实例化委托: 使用匿名方法,可在不定义命名方法的情况下直接编写方法体
MathOperationDelegate mathOperation = delegate (int num1, int num2)
{ return num1 + num2;
};
// 1. 定义委托
public delegate int MathOperationDelegate(int a, int b);class Program
{static void Main(){// 2.实例化委托: 使用匿名方法,可在不定义命名方法的情况下直接编写方法体MathOperationDelegate mathOperation = delegate (int num1, int num2) { return num1 + num2; };}
}
方式4:Lambda 表达式
从C# 3.0开始,可以使用Lambda表达式来创建委托实例。Lambda表达式是一种更简洁的匿名方法语法。
// 实例化委托: 使用 Lambda 表达式MathOperationDelegate mathOperation = (x, y) => x + y;
// 1. 定义委托
public delegate int MathOperationDelegate(int a, int b);class Program
{static void Main(){// 2.实例化委托: 使用 Lambda 表达式MathOperationDelegate mathOperation = (x, y) => x + y;}
}
3)使用委托
通过调用委托,就可以间接的调用委托上对应的方法。
方式1:调用委托变量
传入对应的参数,像调用方法一样调用委托。
mathOperation(4, 5)
public delegate int MathOperationDelegate(int a, int b);class Program
{static void Main(){MathOperationDelegate mathOperation = (x, y) => x + y;Console.WriteLine(mathOperation(4, 5)); //输出:9}
}
方式2:Invoke 调用
使用Invoke
方法,调用委托。使用Invoke
调用委托,如果定义的委托没有参数,则invoke也没有参数,如果定义的委托没有返回值,则invoke也没有返回值。
mathOperation.Invoke(4, 5)
public delegate int MathOperationDelegate(int a, int b);class Program
{static void Main(){MathOperationDelegate mathOperation = (x, y) => x + y;Console.WriteLine(mathOperation.Invoke(4, 5)); //输出:9}
}
2. 示例
1)完整示例代码
// 1. 定义委托
public delegate int MathOperationDelegate(int a, int b);class Program
{// 2.定义委托对应的方法// 注意:该方法的签名必须与定义的委托签名保持一致public static int Add(int num1, int num2){return num1 + num2;}static void Main(){// 3.实例化委托// 实例化方式 1MathOperationDelegate mathOperation1 = new MathOperationDelegate(Add);// 实例化方式 2MathOperationDelegate mathOperation2 = Add;// 实例化方式 3MathOperationDelegate mathOperation3 = delegate (int x, int y){return x + y;};// 实例化方式 4MathOperationDelegate mathOperation4 = (x, y) => x + y;//4. 调用委托// 调用方式 1var reselt1 = mathOperation1(4, 5);Console.WriteLine(reselt1); //输出:9// 调用方式 2var reselt2 = mathOperation4.Invoke(4, 5);Console.WriteLine(reselt2); //输出:9}
}
2)委托基本使用示例
// 1. 定义委托
public delegate int MathOperationDelegate(int a, int b);class Program
{static void Main(){// 2. 实例化委托MathOperationDelegate mathOperation = (x, y) => x + y;// 3. 调用委托Console.WriteLine(mathOperation.Invoke(4, 5)); //输出:9}
}
3. 为什么使用委托
- 解耦代码:分离方法定义与调用逻辑,例如事件处理、异步回调。
- 实现回调机制:委托提供了灵活的回调机制,可以在方法执行完成时触发特定的操作。
- 提高代码复用性:通过委托,可以将通用的处理逻辑提取出来,减少重复代码。
- 灵活性和扩展性:委托允许你在运行时动态地指定要调用的方法,使得代码更加灵活和易于扩展。
- 异步编程支持:委托支持异步编程模型,使得你可以轻松地编写异步操作。
- 支持事件驱动:通过事件封装委托,实现发布-订阅模式
三、委托的特性
1. 多播委托
1)基本信息
委托可以关联多个方法,形成多播委托。多播委托通过 +=
或 -=
操作符来添加或移除关联方法,形成一个委托链。当调用这个委托链时,所有关联的方法按添加的顺序依次执行。
2)多播委托特点
- 委托链:多播委托可以看作是一个委托链,其中每个节点代表一个方法。
- 操作符支持:通过
+=
操作符添加方法,通过-=
操作符移除方法。 - 调用顺序:当调用一个多播委托时,会按照它们被添加的顺序依次调用每个方法。
- 返回值:如果委托有返回值,只有最后一个方法的返回值会被保留,其他返回值会被丢弃。
- 异常处理:如果其中一个方法抛出异常,则后续的方法将不会被调用,除非使用特殊的方式处理异常(如捕获异常并继续执行)。
3)使用示例
为了更好地理解多播委托的工作原理,我们来看一个具体的示例。
首先,定义一个简单的委托类型,并编写几个方法:
using System;// 定义一个委托类型
public delegate void MathOperation(int a, int b);public class Calculator
{public void Add(int a, int b){Console.WriteLine($"Add: {a} + {b} = {a + b}");}public void Subtract(int a, int b){Console.WriteLine($"Subtract: {a} - {b} = {a - b}");}public void Multiply(int a, int b){Console.WriteLine($"Multiply: {a} * {b} = {a * b}");}
}
接下来,我们将这些方法绑定到一个多播委托实例中,并依次调用它们:
public class Program
{static void Main(){Calculator calculator = new Calculator();// 创建委托实例并绑定方法MathOperation operation = calculator.Add;operation += calculator.Subtract;operation += calculator.Multiply; //添加方法operation -= calculator.Multiply; //移除方法// 调用多播委托operation(5, 3);}
}
当你运行上述代码时,输出将是:
Add: 5 + 3 = 8
Subtract: 5 - 3 = 2
可以看到,方法 Add
、Subtract
都被依次调用了,由于Multiply
方法使用-=
移除,所以没被调用 。
4)获取委托链中的方法
有时你可能需要获取多播委托链中的所有方法,以便进行进一步的处理或调试。可以通过 GetInvocationList()
方法来实现这一点。
public class Program
{static void Main(){Calculator calculator = new Calculator();// 创建委托实例并绑定方法MathOperation operation = calculator.Add;operation += calculator.Subtract;operation += calculator.Multiply;// 获取委托链中的所有方法Delegate[] delegates = operation.GetInvocationList();foreach (MathOperation method in delegates){Console.WriteLine($"Calling method: {method.Method.Name}");method(5, 3);}}
}
输出结果
Calling method: Add
Add: 5 + 3 = 8
Calling method: Subtract
Subtract: 5 - 3 = 2
Calling method: Multiply
Multiply: 5 * 3 = 15
5)返回值处理
多播委托的返回值是最后一个被调用的方法的返回值。如果你希望获取所有方法的返回值,可以通过遍历委托链中的方法逐一调用并收集结果。
假设我们有一个带返回值的委托类型:
public delegate int MathOperationWithReturn(int a, int b);public class Calculator
{public int Add(int a, int b){return a + b;}public int Subtract(int a, int b){return a - b;}public int Multiply(int a, int b){return a * b;}
}public class Program
{static void Main(){Calculator calculator = new Calculator();// 创建委托实例并绑定方法MathOperationWithReturn operation = calculator.Add;operation += calculator.Subtract;operation += calculator.Multiply;// 调用多播委托并获取最后一个方法的返回值int result = operation(5, 3);Console.WriteLine($"Last method's result: {result}");// 获取所有方法的返回值Delegate[] delegates = operation.GetInvocationList();foreach (MathOperationWithReturn method in delegates){int tempResult = method(5, 3);Console.WriteLine($"{method.Method.Name} returned: {tempResult}");}}
}
输出结果
Last method's result: 15
Add returned: 8
Subtract returned: 2
Multiply returned: 15
6)异常处理
如果多播委托链中的某个方法抛出异常,默认情况下后续的方法将不会被调用。为了避免这种情况,可以在调用每个方法时捕获异常并继续执行。
public class Program
{static void Main(){Calculator calculator = new Calculator();// 创建委托实例并绑定方法MathOperation operation = calculator.Add;operation += ThrowException; // 这个方法会抛出异常operation += calculator.Multiply;// 调用多播委托并处理异常InvokeAll(operation, 5, 3);}public static void ThrowException(int a, int b){throw new InvalidOperationException("An exception occurred!");}public static void InvokeAll(MathOperation operation, int a, int b){Delegate[] delegates = operation.GetInvocationList();foreach (MathOperation method in delegates){try{Console.WriteLine($"Calling method: {method.Method.Name}");method(a, b);}catch (Exception ex){Console.WriteLine($"Caught exception in {method.Method.Name}: {ex.Message}");}}}
}
输出结果
Calling method: Add
Add: 5 + 3 = 8
Calling method: ThrowException
Caught exception in ThrowException: An exception occurred!
Calling method: Multiply
Multiply: 5 * 3 = 15
2. 泛型委托
1)自定义泛型委托
// 1. 定义委托
public delegate T MathOperationDelegate<T>(T a, T b);class Program
{static void Main(){// 2. 实例化委托MathOperationDelegate<int> mathOperation1 = (x, y) => x + y;MathOperationDelegate<double> mathOperation2 = (x, y) => x - y;// 3. 调用委托Console.WriteLine(mathOperation1.Invoke(4, 5)); //输出:9Console.WriteLine(mathOperation2.Invoke(45.5, 25.1)); //输出:20.4}
}
建议:C#
提供了一些内置的泛型委托类型,如 Func<T>
、Action<T>
和 Predicate<T>
,这些内置委托已经涵盖了大多数常见的场景。除非有特殊需求,否则建议直接使用这些内置委托,而不是重新定义新的委托类型。
2)内置通用委托
C# 提供了一些内置的泛型委托类型,如 Func<T>
和 Action<T>
、Predicate<T>
,简化了委托的定义和使用。
对比表格
特性 | Action<T> 系列 | Func<T> 系列 | Predicate<T> |
---|---|---|---|
定义 | 表示一个没有返回值的委托 | 表示一个有返回值的委托 | 表示一个返回bool 的委托 |
泛型参数数量 | 0到16个输入参数, 无返回值 | 0到16个输入参数, 最后一个表示返回值且只有一个 | 固定1个输入参数, 返回布尔值 |
返回值类型 | void | 可以是任意类型 | bool |
使用场景 | 执行某些操作但不需要返回结果 | 执行某些计算或处理并返回结果 | 判断某个条件是否满足 |
常见用法 | 处理事件、执行副作用操作 | 计算、查询、转换等需要返回结果的操作 | 过滤集合元素、验证条件 |
Action<T>
系列
- 定义:
Action<T>
是一个不带返回值的委托类型,可以接受0到16个输入参数。 - 泛型参数:
Action
本身表示无参数的委托,Action<T>
表示接受一个参数的委托,依此类推,最多可以接受16个参数。 - 返回值:
void
,即没有返回值。 - 典型应用:
- 执行某些操作,如日志记录、文件写入等。
- 处理事件回调函数。
public class Program
{static void Main(){//实例化方式 1Action action = new Action(Show);action();//实例化方式 2action = Show;action();//实例化方式 3action = delegate () { Console.WriteLine("hello"); };action();//实例化方式 4// Action 无参数Action log = () => Console.WriteLine("Logging...");log();// Action<T> 单个参数Action<string> printMessage = message => Console.WriteLine(message);printMessage("Hello, World!");// Action<T1, T2> 多个参数Action<int, int> addAndPrint = (a, b) => Console.WriteLine(a + b);addAndPrint(5, 3);}public static void Show(){Console.WriteLine("hello world!");}
}
Func<T>
系列
- 定义:
Func<T>
是一个带有返回值的委托类型,可以接受0到16个输入参数,并且必须有一个返回值。 - 泛型参数:
Func<TResult>
表示无参数但有返回值的委托,Func<T, TResult>
表示接受一个参数并返回结果的委托,依此类推,最多可以接受16个参数。 - 返回值:最后一个泛型参数指定返回值的类型。
- 典型应用:
- 执行计算、查询、转换等需要返回结果的操作。
- 数据处理和映射。
public class Program
{static void Main(){// Func<TResult> 无参数但有返回值Func<int> getRandomNumber = () => new Random().Next(1, 100);Console.WriteLine(getRandomNumber());// Func<T, TResult> 单个参数Func<int, int> square = x => x * x;Console.WriteLine(square(5));// Func<T1, T2, TResult> 多个参数Func<int, int, int> add = (a, b) => a + b;Console.WriteLine(add(5, 3));}
}
Predicate<T>
- 定义:
Predicate<T>
是一个返回布尔值的委托类型,专门用于判断某个条件是否满足。它只接受一个输入参数。 - 泛型参数:固定为一个参数类型。
- 返回值:
bool
,用于表示条件是否成立。 - 典型应用:
- 集合过滤、元素验证等场景。
- 条件判断。
public class Program
{static void Main(){List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };// Predicate<T> 判断数字是否大于3Predicate<int> isGreaterThanThree = n => n > 3;// 使用 Find 方法查找第一个符合条件的元素int result = numbers.Find(isGreaterThanThree);Console.WriteLine(result); // 输出: 4// 使用 Where 方法过滤所有符合条件的元素var filteredNumbers = numbers.Where(n => isGreaterThanThree(n));foreach (var num in filteredNumbers){Console.WriteLine(num); // 输出: 4, 5}}
}
Predicate<int> isGreaterThanThree = n => n > 3;// 使用 Find 方法查找第一个符合条件的元素
int result = numbers.Find(isGreaterThanThree);
//等效于
int result = numbers.Find(x => x > 3);var filteredNumbers = numbers.Where(n => isGreaterThanThree(n));
//等效于var filteredNumbers = numbers.Where(x => x > 3);
Predicate<T>
在 此处Find
和 Where
中的作用就是筛选出符合条件的数据。当数据符合条件,返回true
,将符合条件的数据返回或加入到新的序列中,返回新的序列。
3)小结
Action<T>
表示一个没有返回值的委托,Action<T>
相当于是对所有 无返回值委托的进一步包装Func<T>
表示一个有返回值的委托,Func<T>
相当于是对所有 有返回值委托的进一步包装Action<T>
和Func<T>
内置委托基本已经涵盖了所有的委托使用场景,除非有特殊需求,否则建议直接使用这些内置委托,而不是重新定义新的委托类型。Func<T>
表示一个返回bool
的委托,Func<T>
相当于是对所有 返回bool
委托的进一步包装
3. 异步委托
委托支持异步调用,可以使用 BeginInvoke
和 EndInvoke
方法进行异步操作。
BeginInvoke
开启一个线程去执行委托BeginInvoke
和EndInvoke
方法 仅 NetFamework支持 ,NetCore中更推荐async/await
using System;
using System.Reflection;public delegate int MathOperation(int a, int b);public class Calculator
{public int Add(int a, int b){Console.WriteLine(MethodBase.GetCurrentMethod().Name);return a + b;}public int Subtract(int a, int b){Console.WriteLine(MethodBase.GetCurrentMethod().Name);return a - b;}
}
class Program
{static void Main(){Calculator calculator = new Calculator();MathOperation operation = calculator.Add;// 异步调用委托IAsyncResult result = operation.BeginInvoke(5, 3, null, null);// 在主线程继续执行其他操作Console.WriteLine("Doing other work...");// 等待异步调用完成并获取结果int sum = operation.EndInvoke(result);Console.WriteLine($"Sum: {sum}"); // 输出: Sum: 8}
}
运行结果:
Doing other work...
Add
Sum: 8
如果是使用Invoke 方法同步执行:
class Program
{static void Main(){Calculator calculator = new Calculator();MathOperation operation = calculator.Add;// 同步调用委托int sum = operation.Invoke(5, 3);// 继续执行其他操作Console.WriteLine("Doing other work...");// 输出结果Console.WriteLine($"Sum: {sum}"); // 输出: Sum: 8}
}
结果如下
Add
Doing other work...
Sum: 8
四、委托的最佳实践
1. 优先使用内置委托
优先使用内置委托,减少冗余代码,提升可维护性。 C# 提供了 Action
和 Func
、Predicate
类型,用于表示常见的委托类型。在大多数情况下,建议使用 Action
和 Func
类型,而不是自定义委托类型。
2. 使用 Lambda 表达式
Lambda 表达式提供了简洁的语法,用于表示匿名函数。在大多数情况下,建议使用 Lambda 表达式,而不是匿名委托或命名方法。
3. 避免过度使用委托
虽然委托非常灵活,但在某些情况下,过度使用委托可能会导致代码难以阅读和维护。在设计代码时,应权衡委托的灵活性和代码的可读性。
5. 避免复杂的委托链
虽然委托链功能强大,但过于复杂的委托链会使代码难以维护。尽量保持委托链简单明了。
4. 注意线程安全性
在多线程环境中使用委托时,需要注意线程安全性问题。确保在访问共享资源时使用适当的同步机制。
// 错误的委托调用方式
public class UnsafeInvoker
{public Action Callback;public void DoWork(){if (Callback != null) // ❌ 非原子操作{Callback(); // ❌ 可能已被置空}}
}// 正确方式
public void SafeDoWork()
{var localCopy = Callback;if (localCopy != null){localCopy();}
}
5. 合理选择委托或事件
需要解耦通知机制时用事件,动态调用方法时用委托。
6. 注意闭包变量生命周期
避免意外捕获外部变量导致内存泄漏。
五、应用场景
1. 应用场景概览
- 事件处理:委托常用于事件处理机制,使得对象可以订阅和触发事件。
- 回调函数:委托可以用来实现回调函数,使得一个方法可以在另一个方法完成后被调用。
- 异步编程:委托支持异步编程模型,使得你可以轻松地编写异步操作。
- 多播委托:委托可以封装多个方法,并按顺序调用这些方法。
2. 应用场景示例
示例1:事件处理
委托是C#中事件处理的基础,委托常用于事件处理机制。以下是一个简单的事件处理示例:
public class Button
{// 定义一个委托类型public delegate void ClickEventHandler(object sender, EventArgs e);// 定义一个事件public event ClickEventHandler Click;// 触发事件public void OnClick(){Click?.Invoke(this, EventArgs.Empty);}
}class Program
{static void Main(){Button button = new Button();// 订阅事件button.Click += (sender, e) =>{Console.WriteLine("Button clicked!");};// 触发事件button.OnClick(); // 输出: Button clicked!}
}
示例2:回调函数
委托可以用来实现回调函数,使得一个方法可以在另一个方法完成后被调用。
public class TaskManager
{public void ExecuteTask(Action callback){Console.WriteLine("Executing task...");// 模拟任务执行System.Threading.Thread.Sleep(1000);Console.WriteLine("Task completed.");// 调用回调函数callback();}
}class Program
{static void Main(){TaskManager taskManager = new TaskManager();// 定义回调函数Action callback = () => Console.WriteLine("Callback executed!");// 执行任务并传递回调函数taskManager.ExecuteTask(callback);}
}
输出结果:
Executing task...
Task completed.
Callback executed!
示例3: 回调函数
委托可以用作回调函数,当某个操作完成时,调用委托来通知调用者。例如:
public delegate void MyDelegate(string message);public class DataLoader
{public void LoadData(MyDelegate callback){// 模拟数据加载System.Threading.Thread.Sleep(1000);callback("Data loaded successfully!");}
}
public class Program
{public static void Main(){DataLoader loader = new DataLoader();loader.LoadData(DisplayMessage);}public static void DisplayMessage(string message){Console.WriteLine(message);}
}
示例4:异步编程
委托支持异步编程模型,使得你可以轻松地编写异步操作。
public class AsyncOperation
{public void PerformOperation(Func<int, int, int> operation, int a, int b){Console.WriteLine("Starting asynchronous operation...");var result = operation.BeginInvoke(a, b, null, null);// 在主线程继续执行其他操作Console.WriteLine("Doing other work...");// 获取异步操作的结果int sum = operation.EndInvoke(result);Console.WriteLine($"Result: {sum}");}
}class Program
{static void Main(){AsyncOperation asyncOperation = new AsyncOperation();// 定义异步操作Func<int, int, int> addFunc = (x, y) =>{Console.WriteLine("Add Operation");return x + y;};// 执行异步操作asyncOperation.PerformOperation(addFunc, 5, 3);}
}
运行结果:
Starting asynchronous operation...
Doing other work...
Add Operation
Result: 8
示例5:异步流水线处理
虽然委托支持使用BeginInvoke
异步调用,但在现代C#中,推荐使用 async
和 await
来实现异步操作。这种方式更加直观和易于维护。
using System;
using System.Threading.Tasks;public class Program
{public static async Task PipelineProcessingAsync(){// 定义下载数据的操作Func<string, Task<string>> download = async url => {await Task.Delay(100); // 模拟网络延迟return $"Data from {url}";};// 定义处理数据的操作Func<string, Task<string>> process = async data => {await Task.Delay(50); // 模拟处理时间return data.ToUpper();};// 定义保存结果的操作Func<string, Task> save = async result => {await Task.Delay(20); // 模拟保存时间Console.WriteLine($"Saved: {result}");};// 构建处理流水线async Task ProcessPipeline(string url){var downloadedData = await download(url);var processedData = await process(downloadedData);await save(processedData);}// 执行处理流水线await ProcessPipeline("http://example.com");}// NetFamework 下的写法public static void Main(string[] args){ PipelineProcessingAsync().GetAwaiter().GetResult();//输出:Saved: DATA FROM HTTP://EXAMPLE.COM}
}
NetCore下的写法
public static async void Main(string[] args){await PipelineProcessingAsync();//输出:Saved: DATA FROM HTTP://EXAMPLE.COM}
示例6:动态方法选择器
public class CommandDispatcher
{private readonly Dictionary<string, Action<string>> _handlers = new Dictionary<string, Action<string>>();public void RegisterHandler(string command, Action<string> handler){_handlers[command] = handler;}public void Execute(string command, string parameter){if (_handlers.TryGetValue(command, out var handler)){handler(parameter);}else{throw new InvalidOperationException($"未知命令: {command}");}}
}
示例7:策略模式实现
public class PaymentProcessor
{private Func<Order, PaymentResult> _paymentStrategy;public void SetPaymentStrategy(Func<Order, PaymentResult> strategy){_paymentStrategy = strategy;}public PaymentResult Process(Order order){return _paymentStrategy?.Invoke(order) ?? throw new InvalidOperationException("未设置支付策略");}
}// 使用示例
processor.SetPaymentStrategy(CreditCardStrategy);
var result = processor.Process(order);
示例8:动态方法调用
通过反射动态绑定委托,适用于插件化架构:
using System;
using System.Reflection;public class Utility
{// Encrypt 方法接受一个字符串参数并返回加密后的字符串public static string Encrypt(string input){// 简单的加密逻辑(实际应用中应使用更安全的加密算法)char[] chars = input.ToCharArray();for (int i = 0; i < chars.Length; i++){chars[i] = (char)(chars[i] + 1); // 将每个字符编码值加1}return new string(chars);}
}public class Program
{public static void Main(string[] args){// 获取 Utility 类中的 Encrypt 方法MethodInfo method = typeof(Utility).GetMethod("Encrypt", BindingFlags.Public | BindingFlags.Static);if (method == null){Console.WriteLine("未能找到 Encrypt 方法。");return;}// 使用反射创建 Func<string, string> 委托实例Delegate delegateInstance = Delegate.CreateDelegate(typeof(Func<string, string>), method);if (delegateInstance == null){Console.WriteLine("未能创建委托实例。");return;}// 将 delegateInstance 转换为 Func<string, string>Func<string, string> encryptFunc = (Func<string, string>)delegateInstance;// 调用委托实例string originalText = "Hello, World!";string encryptedText = encryptFunc(originalText);Console.WriteLine($"原始文本: {originalText}");Console.WriteLine($"加密后的文本: {encryptedText}");}
}
示例9:表达式树
// 传统匿名方法
MathOperation sqrt = delegate(int x) { return Math.Sqrt(x); };// Lambda表达式
MathOperation sqrt = x => Math.Sqrt(x);// 表达式树(编译时转换为委托)
Expression<Func<int, double>> expr = x => Math.Sqrt(x);
var compiled = expr.Compile();
public class Program
{public static void Main(){Expression<Func<int, double>> expr = x => Math.Sqrt(x);var compiled = expr.Compile();Console.WriteLine(compiled.Invoke(16)); //输出:4}
}
结语
回到目录页:C#/.NET 知识汇总
希望以上内容可以帮助到大家,如文中有不对之处,还请批评指正。
参考资料:
Microsoft Docs: 事件
Microsoft Docs: 异步编程
Microsoft Docs: 委托文档