2009-09-18 106 views
19

我試圖寫入API,當我從表中獲取數據時需要調用事件處理程序。事情是這樣的:通過EventHandler返回返回值

public override bool Run(Company.API api) 
    { 
     SomeInfo _someInfo = new SomeInfo(); 

     if (_someInfo.Results == 1) 
      return true; 
     else 
      return false; 

     using (MyTable table = new MyTable(api)) 
     { 
      table.WhenData += new EventHandler<DataEventArgs<Record>>(table_WhenData); 
      table.WhenDead += new EventHandler<EventArgs>(table_WhenDead); 
      table.Start(); 
     } 

    public void table_WhenData(object sender, DataEventArgs<Record> e) 
    { 
     return true; 
    } 

具有即時通訊是我不知道如何傳遞一個返回值從table_WhenData回到Run方法的問題。

我試過很多方法(如試圖將_someInfo傳遞給方法),但我似乎無法得到正確的語法。

任何建議,非常感謝。

+0

事件處理程序如預期從某處調用。這不是在你的代碼中顯示?這是唯一可以檢查處理程序返回的地方。 – simon 2009-09-18 18:46:17

+0

謝謝大家。因爲這是一個API,有很多代碼沒有訪問權限,或者我無法更改。我只是想在將它發回給開發者之前進行驗證。謝謝。 – 2009-09-18 19:03:52

+2

用戶名加上1 – 2015-12-18 13:19:42

回答

38

這裏的常見模式不是從事件處理程序返回任何數據,而是爲事件參數對象添加屬性,以便事件的使用者可以設置調用者可以訪問的屬性。這在UI處理代碼中非常常見;你會在整個地方看到取消事件的概念。

以下是僞代碼,未編譯就緒。其目的是展示這種模式。

public MyEventArgs : EventArgs 
{ 
    public bool Cancel{get;set;} 
} 

public bool fireEvent() 
{ 
    MyEventArgs e=new MyEventArgs(); 

    //Don't forget a null check, assume this is an event 
    FireEventHandler(this,e); 

    return e.Cancel; 
} 

public HandleFireEvent(object sender, MyEventArgs e) 
{ 
e.Cancel=true; 
} 

編輯

我喜歡喬恩斯基特如何措辭是:使EventArgs mutuable。也就是說,事件的消費者可以修改對象的狀態,從而允許事件的發起者獲取該數據。

+1

如果有多個事件處理程序(有些將其設置爲true,另一個則將此對象值設置爲false,對於上面給出的代碼示例),事件訂閱者代碼如何確定?就像是最後一個訂閱者贏得的那樣 – bashahul 2016-06-11 07:08:57

+1

好的問題你可能會想要在這種情況下使用不同的數據結構,具體取決於你擁有的業務規則 – JoshBerke 2016-06-13 13:32:32

15

你可以做到這一點的唯一方法是使其中一個參數(最好是「參數」而不是發送者)可變。如果它還不是可變的,那麼你基本上就會遇到問題 - 沒有辦法將信息輸出。

(好的,有一種方法 - 你可以保持事件參數本身不變,但讓它的一個成員變成一個方法,最終調用代碼註冊的代碼首先提升事件,但這太可怕了。 ..)

+2

我的頭痛會試圖理解一種方式,請讓EventArgs變得可變! – JoshBerke 2009-09-18 18:50:28

+0

如何在我的回覆中描述使用閉包? – 2009-09-18 18:51:41

+0

伊戈爾:這將工作,但通常需要結果的代碼位不是預訂事件的代碼位。 – 2009-09-18 18:57:52

1

一個簡單的解決方案是使用封閉:

public override bool Run() { 
    SomeInfo someInfo = ... 
    table.WhenData += (obj, args) => { 
     someInfo.Return = something 
    }; 
} 
+0

我對這個解決方案可能有的擔心是併發問題。一個線程調用該事件,另一個線程在寫入完成之前讀取someInfo變量。它需要某種類型的多線程保護。 – simon 2009-09-19 00:51:33

17

我知道這是一個古老的職位,但以防萬一有人遇到它,它肯定是有可能做到這一點。你聲明你自己的委託,它返回一個值,然後根據這個新委託來關閉事件。下面是一個例子:

在事件莊家/出版者:

// the delegate 
public delegate string ReturnStringEventHandler(object sender, EventArgs args); 
// the event 
public event ReturnStringEventHandler StringReturnEvent; 
// raise the event 
protected void OnStringReturnEvent(EventArgs e) 
    { 
     if (StringReturnEvent != null) // make sure at least one subscriber 
       // note the event is returning a string 
       string myString = StringReturnEvent(this, e); 
    } 

在事件訂閱者:

// Subscribe to event, probably in class constructor/initializer method 
StringReturnEvent += HandleStringReturnEvent; 

// Handle event, return data 
private string HandleStringReturnEvent(object sender, EventArgs e) 
{ 
    return "a string to return"; 
} 

.NET提供在AssemblyResolve事件的一個例子,它使用ResolveEventHandler委託返回數據,在這種情況下是對所需Assembly的引用。 MSDN Article on AssemblyResolve event

我曾親自使用兩個AssemblyResolve事件和自定義委託技術,從事件中返回的數據,他們都工作在Visual Studio 2010中

+2

如果使用自定義委託方法,如果有多個處理程序返回不同的值,會發生什麼情況?事件提升者收到哪個返回值? – Shavais 2013-12-05 20:27:10

+0

您提到了這種方法的明確缺點。要在事件中註冊的最後一個事件處理程序是其值將被返回的那個。 http://msdn.microsoft.com/en-us/library/aa691375%28VS.71%29.aspx在我提到的「AssemblyResolve」事件中,這是可以的,因爲它的唯一意圖是一次只能使用一個,但你是對的 - 一般來說,如果需要多個返回值,這將是一個糟糕的設計選擇。 – AFischbein 2013-12-06 14:48:55

+0

輝煌。謝謝 ! – BillW 2014-03-23 16:26:21