簡體   English   中英

C#:如何立即在父事件完成執行之前引發子事件?

[英]C#: How do I raise a child event immediately before the parent event finish executing?

我正在利用第三方的API來控制其硬件。 他們的方法將永遠不會返回值,而只會觸發將返回已更改的值或更改值時發生異常的事件。 我想這就像UI事件。

假設有一個事件處理程序button_Click() ,除其他功能外,我還使用它來調用函數ThirdPartyAPI.SetSomeStuffConfig(some parameters...) 調用該第三方函數后,我需要立即訪問只能通過該函數事件的事件處理程序訪問的值或異常。 問題是,由第三方函數引發的事件僅在button_Click()完成后才執行。

有什么解決方案或編碼模式可用於解決此問題? button_Click()的事件處理程序完成執行之前,是否可以觸發並運行第三方的事件/事件處理程序?

即,我想在button_Click()調用第三方函數后立即訪問值和異常。

嘗試解決方案

我嘗試過的是將button_Click()分為兩部分。 調用ThirdPartyAPI.SetSomeStuffConfig(some parameters...)之后出現的部分將放入第三方的事件處理程序中。 然而,這是非常麻煩和限制性的。

第三方API的示例代碼

public void Stuff_SetConfig(int id, int mode, string Exception)
{

   //returns the new ID, Mode and exception if unable to set ID or Mode on the hardware
    this.ID = id;
    this.Mode = mode;
}

private void button_Click(object sender, EventArgs e)
{
    ThirdParty.Stuff newStuff = new ThirdParty.Stuff();
    newStuff.StuffSetConfig += new ThirdParty.IThirdPartyStuffEvents_StuffSetConfigEventHandler(Stuff_SetConfig);
    //call some functions...

    newStuff.SetConfig(5, 10); //triggers StuffSetConfigEventHandler
    //call other functions...
    Console.WriteLine("ID is " + this.ID + " and this.Mode is " + this.Mode); //ID and Mode is empty because the Stuff_SetConfig event handler has not yet run.
}

(取決於您要包裝的API,類似於EAP)。

基於事件的異步模式 (EAP)中,您調用異步方法並期望在工作完成時引發事件-無論成功還是失敗。 這是在.NET中編寫異步代碼的較舊模式。 當Microsoft引入Task ,尤其是在它們添加asyncawait該語言之后,人們開始對舊模式進行調整以使其看起來像基於任務的異步模式 (TAP)的現代Task返回方法,引起了很多興趣。

不幸的是,轉換EAP並不像適應舊版APM(.NET的原始異步模式)那樣簡單。 但是,他們確實提供了這樣做的指導 他們的示例是帶有DownloadFileAsync方法和DownloadFileCompleted事件的較舊的WebClient類。 這是他們的改編:

 public static Task<string> DownloadStringAsync(Uri url) { var tcs = new TaskCompletionSource<string>(); var wc = new WebClient(); wc.DownloadStringCompleted += (s,e) => { if (e.Error != null) tcs.TrySetException(e.Error); else if (e.Cancelled) tcs.TrySetCanceled(); else tcs.TrySetResult(e.Result); }; wc.DownloadStringAsync(url); return tcs.Task; } 

因此,如果您可以使用第三方API進行類似操作,則可以創建包裝器,並假裝其方法是Task返回的。 一旦知道了這一點,您就可以在button_click處理程序中間awaitTask


用一種方法完成所有操作,我們可以濫用捕獲來走私多個結果,但是我建議將TaskCompletionSource內容放入上述單獨的方法中,並以不同的方式處理多個結果(C#7元組?):

private async void button_Click(object sender, EventArgs e)
{
    ThirdParty.Stuff newStuff = new ThirdParty.Stuff();

    //call some functions...

    var tcs = new TaskCompletionSource<int>();
    int mode;
    newStuff.SetConfig += (_id, _mode, ex) =>
    {
       if(!string.IsNullOrWhitespace(ex))
       {
          tcs.TrySetException(new Exception(ex));
       }
       else
       {
          mode = _mode;
          tcs.TrySetResult(_id);
       }
    }
    newStuff.SetConfig(5, 10);
    //call other functions...
    var id = await tcs.Task;
    Console.WriteLine("ID is " + id + " and this.Mode is " + mode);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM