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