马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
总目次
前言
在C#中,委托(Delegate)提供了多种调用方式,包罗 Invoke、BeginInvoke、EndInvoke 和 DynamicInvoke。每种调用方式都有其特定的用途和实用场景。下面将详细先容这些方法的区别与接洽。
一、 Invoke方法
1. 界说
Invoke 是同步调用委托的方法。它会壅闭当火线程,直到委托所引用的方法实验完毕并返回效果。
2. 特点
- 同步调用:当火线程会被壅闭,直到委托方法实验完成。
- 简朴直接:实用于不须要异步处置处罚的场景。
3. 示例代码
- public class Program
- {
- public static void Main()
- {
- // 定义委托
- Action action = () => Console.WriteLine("Hello, World!");
- // 同步调用
- action.Invoke();
- }
- }
复制代码- public class Program
- {
- public delegate string SimpleDelegate(string message);
- public static string PrintMessage(string message)
- {
- Console.WriteLine($"Message: {message}");
- return "Done";
- }
- public static void Main()
- {
- SimpleDelegate del = PrintMessage;
- string result = del.Invoke("Hello, World!"); // 同步调用
- Console.WriteLine(result);
- }
- }
复制代码 输出效果
- Message: Hello, World!
- Done
复制代码 二、 BeginInvoke 和 EndInvoke 方法
1. 界说
BeginInvoke 和 EndInvoke 方法用于异步调用委托所引用的方法。BeginInvoke 方法启动异步使用并立刻返回一个 IAsyncResult 对象,该对象可以用于跟踪异步使用的状态。而 EndInvoke 方法用于获取异步调用的效果或等待异步调用完成。
2. 特点
- BeginInvoke
- 异步调用:当火线程不会被壅闭,委托方法将在背景线程上实验。
- 回调机制:可以通过提供一个回调函数,在委托方法完成后自动调用该回调函数。
- 参数转达:除了委托方法的参数外,还须要转达一个 AsyncCallback 委托和一个用户界说的对象(通常是 null)。
- EndInvoke
- 获取效果:通过传入 BeginInvoke 返回的 IAsyncResult 对象来获取异步调用的效果。
- 等待完成:如果异步调用尚未完成,EndInvoke 将壅闭当火线程,直到异步调用完成。
3. 示例代码
- using System;
- public class Program
- {
- public delegate string SimpleDelegate(string message);
- public static string PrintMessage(string message)
- {
- Console.WriteLine($"Message: {message}");
- return "Done";
- }
- public static void Main()
- {
- SimpleDelegate del = PrintMessage;
- IAsyncResult asyncResult = del.BeginInvoke("Hello, World!", null, null); // 异步调用
- Console.WriteLine("Main method continues...");
- // 等待异步调用完成并获取结果
- string result = del.EndInvoke(asyncResult);
- Console.WriteLine(result);
- }
- }
复制代码 输出效果
- Main method continues...Message: Hello, World!
- Done
复制代码- using System;
- using System.Threading;
- public class Program
- {
- public static void Main()
- {
- // 定义委托
- Func<int> func = () =>
- {
- Thread.Sleep(2000);
- Console.WriteLine("Asynchronous operation completed.");
- return 42;
- };
- // 异步调用
- IAsyncResult result = func.BeginInvoke(null, null);
- // 执行其他操作
- Console.WriteLine("Performing other tasks while waiting...");
- // 等待异步操作完成并获取结果
- int returnValue = func.EndInvoke(result);
- Console.WriteLine($"Return value: {returnValue}");
- }
- }
复制代码 三、DynamicInvoke 方法
1. 界说
DynamicInvoke 是一种动态调用委托的方法,允许以恣意范例的参数调用委托,而不须要指定详细的参数范例。
与 Invoke 差别,DynamicInvoke 可以在运行时动态地确定要调用的方法,而且可以处置处罚参数和返回值的范例。
2. 特点
- 机动性高:可以在运行时动态确定参数范例和数量。
- 性能较低:由于须要举行范例查抄和转换,性能通常低于直接调用(如 Invoke 或 BeginInvoke)。
3. 示例代码
- using System;
- public class Program
- {
- public delegate string SimpleDelegate(string message);
- public static string PrintMessage(string message)
- {
- Console.WriteLine($"Message: {message}");
- return "Done";
- }
- public static void Main()
- {
- SimpleDelegate del = PrintMessage;
- object[] args = new object[] { "Hello, DynamicInvoke!" };
- string result = (string)del.DynamicInvoke(args); // 动态调用
- Console.WriteLine(result);
- }
- }
复制代码 输出效果
- Message: Hello, DynamicInvoke!
- Done
复制代码- using System;
- public class Program
- {
- public static void Main()
- {
- // 定义委托
- Func<int, int, int> add = (a, b) => a + b;
- // 动态调用
- object result = add.DynamicInvoke(2, 3);
- Console.WriteLine($"Result: {result}"); //输出:Result: 5
- }
- }
复制代码 四、比力与总结
1. 概览
方法调用方式是否壅闭当火线程参数范例要求性能重要应用场景Invoke同步是固定高简朴同步调用BeginInvoke异步否固定中等异步调用EndInvoke同步是固定中等获取异步调用效果DynamicInvoke动态是动态低运行时动态调用2. 详细区别与接洽
- Invoke vs BeginInvoke
- Invoke 是同步调用,会壅闭当火线程直到方法实验完成;BeginInvoke 是异步调用,不会壅闭当火线程。
- Invoke 实用于须要立刻得到效果的场景;BeginInvoke 实用于须要进步相应速率、克制壅闭主线程的场景。
- BeginInvoke vs EndInvoke
- BeginInvoke 用于启动异步调用,返回一个 IAsyncResult 对象;EndInvoke 用于获取异步调用的效果或等待异步调用完成。
- 在使用 BeginInvoke 后,必须调用 EndInvoke 来确保资源开释和获取效果。
- DynamicInvoke
- DynamicInvoke 提供了极大的机动性,但代价是性能较低,由于它须要在运行时举行范例查抄和转换。
- 实用于须要在运行时动态确定参数范例和数量标场景。
3. 实际应用发起
- 同步调用:如果你须要立刻得到效果而且不关心壅闭当火线程,使用 Invoke。
- 异步调用:如果你渴望在不壅闭当火线程的环境下实验某个使用,使用 BeginInvoke 和 EndInvoke。
- 动态调用:如果你须要在运行时动态确定参数范例和数量,使用 DynamicInvoke,但要注意其性能开销。
- 及时数据展示:用 Control.BeginInvoke 异步更新 UI。
- 批量盘算使命:通过 BeginInvoke 分发使命到线程池。
- 插件体系:联合 DynamicInvoke 实现动态方法调用。
通过公道选择调用方式,可以在包管线程安全的同时提拔步调性能与相应速率。
4. 接洽与协作
- 异步调用链:
BeginInvoke 启动异步使命 → 通过 IAsyncResult 监控 状态 → EndInvoke 获取效果,形成完备的异步流程。
- 线程安全:
UI 控件使用中,Control.Invoke 和 Control.BeginInvoke 逼迫在 UI 线程实验委托,克制跨线程访问非常。
- 替换方案:
当代 C# 保举使用 Task 和 async/await 替换 BeginInvoke/EndInvoke,因其代码可读性更高且资源管理更安全。
5. 注意事项
- 性能开销:
BeginInvoke 依靠线程池,频仍调用大概导致资源竞争;DynamicInvoke 的反射机制服从较低,慎用于高频场景。
- 非常处置处罚:
- Invoke 和 DynamicInvoke 的非常直接传播,需用 try-catch 包裹;
- BeginInvoke 的非常需在 EndInvoke 中捕捉。
- 代码优化:
发布模式下,编译器大概内联方法,可通过 [MethodImpl(MethodImplOptions.NoInlining)] 保存堆栈信息。
结语
回到目次页:C#/.NET 知识汇总
渴望以上内容可以资助到各人,如文中有不对之处,还请品评指正。
|