C# 委托中 Invoke/BeginInvoke/EndInvoke和DynamicInvoke 方法的區(qū)別和聯(lián)系
前言
在C#中,委托(Delegate)提供了多種調(diào)用方式,包括 Invoke、BeginInvoke、EndInvoke 和 DynamicInvoke。每種調(diào)用方式都有其特定的用途和適用場景。下面將詳細(xì)介紹這些方法的區(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í)行表達(dá)式樹(Expression Tree)的具體使用
本文將深入探討表達(dá)式樹的基本概念、創(chuàng)建方法、修改和刪除節(jié)點、查詢和遍歷技巧以及在C#中的應(yīng)用示例,具有一定的參考價值,感興趣的可以了解一下2024-03-03
基于WPF實現(xiàn)帶明細(xì)的環(huán)形圖表
這篇文章主要介紹了如何利用WPF繪制帶明細(xì)的環(huán)形圖表?,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)或工作有一定幫助,需要的可以參考一下2022-08-08
深入Resource實現(xiàn)多語言支持的應(yīng)用詳解
本篇文章是對Resource實現(xiàn)多語言支持的應(yīng)用進行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05

