C# 委托中 Invoke/BeginInvoke/EndInvoke和DynamicInvoke 方法的區(qū)別和聯(lián)系
前言
在C#中,委托(Delegate)提供了多種調(diào)用方式,包括 Invoke
、BeginInvoke
、EndInvoke
和 DynamicInvoke
。每種調(diào)用方式都有其特定的用途和適用場(chǎng)景。下面將詳細(xì)介紹這些方法的區(qū)別與聯(lián)系。
一、 Invoke方法
1. 定義
Invoke
是同步調(diào)用委托的方法。它會(huì)阻塞當(dāng)前線(xiàn)程,直到委托所引用的方法執(zhí)行完畢并返回結(jié)果。
2. 特點(diǎn)
- 同步調(diào)用:當(dāng)前線(xiàn)程會(huì)被阻塞,直到委托方法執(zhí)行完成。
- 簡(jiǎn)單直接:適用于不需要異步處理的場(chǎng)景。
3. 示例代碼
public class Program { public static void Main() { // 定義委托 Action action = () => Console.WriteLine("Hello, World!"); // 同步調(diào)用 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!"); // 同步調(diào)用 Console.WriteLine(result); } }
輸出結(jié)果
Message: Hello, World!
Done
二、 BeginInvoke 和 EndInvoke 方法
1. 定義
BeginInvoke
和 EndInvoke
方法用于異步調(diào)用委托所引用的方法。BeginInvoke
方法啟動(dòng)異步操作并立即返回一個(gè) IAsyncResult
對(duì)象,該對(duì)象可以用于跟蹤異步操作的狀態(tài)。而 EndInvoke
方法用于獲取異步調(diào)用的結(jié)果或等待異步調(diào)用完成。
2. 特點(diǎn)
BeginInvoke
- 異步調(diào)用:當(dāng)前線(xiàn)程不會(huì)被阻塞,委托方法將在后臺(tái)線(xiàn)程上執(zhí)行。
- 回調(diào)機(jī)制:可以通過(guò)提供一個(gè)回調(diào)函數(shù),在委托方法完成后自動(dòng)調(diào)用該回調(diào)函數(shù)。
- 參數(shù)傳遞:除了委托方法的參數(shù)外,還需要傳遞一個(gè)
AsyncCallback
委托和一個(gè)用戶(hù)定義的對(duì)象(通常是null
)。
EndInvoke
- 獲取結(jié)果:通過(guò)傳入
BeginInvoke
返回的IAsyncResult
對(duì)象來(lái)獲取異步調(diào)用的結(jié)果。 - 等待完成:如果異步調(diào)用尚未完成,
EndInvoke
將阻塞當(dāng)前線(xiàn)程,直到異步調(diào)用完成。
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); // 異步調(diào)用 Console.WriteLine("Main method continues..."); // 等待異步調(diào)用完成并獲取結(jié)果 string result = del.EndInvoke(asyncResult); Console.WriteLine(result); } }
輸出結(jié)果
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; }; // 異步調(diào)用 IAsyncResult result = func.BeginInvoke(null, null); // 執(zhí)行其他操作 Console.WriteLine("Performing other tasks while waiting..."); // 等待異步操作完成并獲取結(jié)果 int returnValue = func.EndInvoke(result); Console.WriteLine($"Return value: {returnValue}"); } }
三、DynamicInvoke 方法
1. 定義
DynamicInvoke
是一種動(dòng)態(tài)調(diào)用委托的方法,允許以任意類(lèi)型的參數(shù)調(diào)用委托,而不需要指定具體的參數(shù)類(lèi)型。
與 Invoke
不同,DynamicInvoke
可以在運(yùn)行時(shí)動(dòng)態(tài)地確定要調(diào)用的方法,并且可以處理參數(shù)和返回值的類(lèi)型。
2. 特點(diǎn)
- 靈活性高:可以在運(yùn)行時(shí)動(dòng)態(tài)確定參數(shù)類(lèi)型和數(shù)量。
- 性能較低:由于需要進(jìn)行類(lèi)型檢查和轉(zhuǎn)換,性能通常低于直接調(diào)用(如
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); // 動(dòng)態(tài)調(diào)用 Console.WriteLine(result); } }
輸出結(jié)果
Message: Hello, DynamicInvoke!
Done
using System; public class Program { public static void Main() { // 定義委托 Func<int, int, int> add = (a, b) => a + b; // 動(dòng)態(tài)調(diào)用 object result = add.DynamicInvoke(2, 3); Console.WriteLine($"Result: {result}"); //輸出:Result: 5 } }
四、比較與總結(jié)
1. 概覽
方法 | 調(diào)用方式 | 是否阻塞當(dāng)前線(xiàn)程 | 參數(shù)類(lèi)型要求 | 性能 | 主要應(yīng)用場(chǎng)景 |
---|---|---|---|---|---|
Invoke | 同步 | 是 | 固定 | 高 | 簡(jiǎn)單同步調(diào)用 |
BeginInvoke | 異步 | 否 | 固定 | 中等 | 異步調(diào)用 |
EndInvoke | 同步 | 是 | 固定 | 中等 | 獲取異步調(diào)用結(jié)果 |
DynamicInvoke | 動(dòng)態(tài) | 是 | 動(dòng)態(tài) | 低 | 運(yùn)行時(shí)動(dòng)態(tài)調(diào)用 |
2. 具體區(qū)別與聯(lián)系
Invoke
vs BeginInvoke
Invoke
是同步調(diào)用,會(huì)阻塞當(dāng)前線(xiàn)程直到方法執(zhí)行完成;BeginInvoke
是異步調(diào)用,不會(huì)阻塞當(dāng)前線(xiàn)程。Invoke
適用于需要立即得到結(jié)果的場(chǎng)景;BeginInvoke
適用于需要提高響應(yīng)速度、避免阻塞主線(xiàn)程的場(chǎng)景。
BeginInvoke
vs EndInvoke
BeginInvoke
用于啟動(dòng)異步調(diào)用,返回一個(gè)IAsyncResult
對(duì)象;EndInvoke
用于獲取異步調(diào)用的結(jié)果或等待異步調(diào)用完成。- 在使用
BeginInvoke
后,必須調(diào)用EndInvoke
來(lái)確保資源釋放和獲取結(jié)果。
DynamicInvoke
DynamicInvoke
提供了極大的靈活性,但代價(jià)是性能較低,因?yàn)樗枰谶\(yùn)行時(shí)進(jìn)行類(lèi)型檢查和轉(zhuǎn)換。- 適用于需要在運(yùn)行時(shí)動(dòng)態(tài)確定參數(shù)類(lèi)型和數(shù)量的場(chǎng)景。
3. 實(shí)際應(yīng)用建議
- 同步調(diào)用:如果你需要立即得到結(jié)果并且不關(guān)心阻塞當(dāng)前線(xiàn)程,使用
Invoke
。 - 異步調(diào)用:如果你希望在不阻塞當(dāng)前線(xiàn)程的情況下執(zhí)行某個(gè)操作,使用
BeginInvoke
和EndInvoke
。 - 動(dòng)態(tài)調(diào)用:如果你需要在運(yùn)行時(shí)動(dòng)態(tài)確定參數(shù)類(lèi)型和數(shù)量,使用
DynamicInvoke
,但要注意其性能開(kāi)銷(xiāo)。 - 實(shí)時(shí)數(shù)據(jù)展示:用
Control.BeginInvoke
異步更新 UI。 - 批量計(jì)算任務(wù):通過(guò)
BeginInvoke
分發(fā)任務(wù)到線(xiàn)程池。 - 插件系統(tǒng):結(jié)合
DynamicInvoke
實(shí)現(xiàn)動(dòng)態(tài)方法調(diào)用。
通過(guò)合理選擇調(diào)用方式,可以在保證線(xiàn)程安全的同時(shí)提升程序性能與響應(yīng)速度。
4. 聯(lián)系與協(xié)作
- 異步調(diào)用鏈:
- BeginInvoke 啟動(dòng)異步任務(wù) → 通過(guò) IAsyncResult 監(jiān)控狀態(tài) → EndInvoke 獲取結(jié)果,形成完整的異步流程。
- 線(xiàn)程安全:
- UI 控件操作中,Control.Invoke 和 Control.BeginInvoke 強(qiáng)制在 UI 線(xiàn)程執(zhí)行委托,避免跨線(xiàn)程訪(fǎng)問(wèn)異常。
- 替代方案:
- 現(xiàn)代 C# 推薦使用 Task 和 async/await 替代 BeginInvoke/EndInvoke,因其代碼可讀性更高且資源管理更安全。
5. 注意事項(xiàng)
性能開(kāi)銷(xiāo):
BeginInvoke
依賴(lài)線(xiàn)程池,頻繁調(diào)用可能導(dǎo)致資源競(jìng)爭(zhēng);DynamicInvoke
的反射機(jī)制效率較低,慎用于高頻場(chǎng)景。
異常處理:
Invoke
和DynamicInvoke
的異常直接傳播,需用try-catch
包裹;BeginInvoke
的異常需在EndInvoke
中捕獲。
代碼優(yōu)化:
發(fā)布模式下,編譯器可能內(nèi)聯(lián)方法,可通過(guò) [MethodImpl(MethodImplOptions.NoInlining)]
保留堆棧信息。
到此這篇關(guān)于C# 委托中 Invoke/BeginInvoke/EndInvoke和DynamicInvoke 方法的文章就介紹到這了,更多相關(guān)C# 委托 Invoke/BeginInvoke/EndInvoke和DynamicInvoke內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#中BackgroundWorker類(lèi)用法總結(jié)
本文詳細(xì)講解了C#中BackgroundWorker類(lèi)用法總結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-12-12對(duì)WPF中的TreeView實(shí)現(xiàn)右鍵選定
這篇文章介紹了WPF實(shí)現(xiàn)右鍵選定TreeView的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06C#定義簡(jiǎn)單的反射工廠(chǎng)實(shí)例分析
這篇文章主要介紹了C#定義簡(jiǎn)單的反射工廠(chǎng)的用法,實(shí)例分析了反射工廠(chǎng)的原理與使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-04-04C#執(zhí)行表達(dá)式樹(shù)(Expression Tree)的具體使用
本文將深入探討表達(dá)式樹(shù)的基本概念、創(chuàng)建方法、修改和刪除節(jié)點(diǎn)、查詢(xún)和遍歷技巧以及在C#中的應(yīng)用示例,具有一定的參考價(jià)值,感興趣的可以了解一下2024-03-03基于WPF實(shí)現(xiàn)帶明細(xì)的環(huán)形圖表
這篇文章主要介紹了如何利用WPF繪制帶明細(xì)的環(huán)形圖表?,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)或工作有一定幫助,需要的可以參考一下2022-08-08深入Resource實(shí)現(xiàn)多語(yǔ)言支持的應(yīng)用詳解
本篇文章是對(duì)Resource實(shí)現(xiàn)多語(yǔ)言支持的應(yīng)用進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05