Effective C# Item21:使用委託表達回調

    回調用於爲服務器和客戶端之間提供異步的反饋,其中可能會涉及到多線程或者需要提供一個入口點用於同步更新,在C#中,我們使用委託來表達回調。

    委託爲我們提供了類型安全的回調定義,雖然大多數常見的委託應用都和事件相關,但是那並不是委託應用的全部場合。當類之間有通信的需要,並且我們期望一種比接口更加松耦合的機制時,委託就是最合適的選擇。委託允許我們在運行時配置目標,並且可以通知多個對象,委託對象中包含一個方法引用,這個方法可以是靜態方法,也可以是實例方法。

    我們還可以爲委託綁定多個方法,利用委託的多播機制,可以一次調用多個方法。但是有兩點需要注意:1)如果有委託調用出現異常,那麼這種構造將不能保證安全;2)整個多播調用的返回值是最後一個調用的方法的返回值。

    在一個多播委託調用的過程中,每一個目標都會被順次調用,委託對象本身不會捕捉任何異常,因此,任何目標拋出的異常都會結束委託鏈的調用。

    同樣,委託的返回值也有同樣的問題,如果委託的返回值類型不是void,那麼對於一個多播委託來說,最後的返回值就是委託鏈上執行的最後一個方法,其他的返回值都會被忽略。

    我們來看下面的代碼。

public delegate bool ContinueProcessing();

public void LengthyOperation( ContinueProcessing pred )
{
  foreach( ComplicatedClass cl in _container )
  {
    cl.DoLengthyOperation();
    // Check for user abort:
    if (false == pred())
      return;
  }
}


//Test
ContinueProcessing cp = new ContinueProcessing ( CheckWithUser );
cp += new ContinueProcessing( CheckWithSystem );
c.LengthyOperation( cp );


    上述代碼在執行過程中,就會忽略CheckWithUser()方法的返回值。

    我們可以自己手動遍歷委託鏈來解決這個問題,來看下面的代碼。

 public delegate bool ContinueProcessing();

 public void LengthyOperation( ContinueProcessing pred )
{
  bool bContinue = true;
  foreach( ComplicatedClass cl in _container )
  {
    cl.DoLengthyOperation();
    foreach( ContinueProcessing pr in  pred.GetInvocationList( ))

      bContinue &= pr();

    if (false == bContinue)
      return;
  }
}

 

    上述代碼中,我們調用GetInvocationList()方法來手動遍歷委託鏈,這樣就可以解決上面提到的CheckWithUser()方法返回值被忽略的問題。

    委託爲我們提供了一種在運行時進行回調的最好方式,這種方式對客戶類只有非常簡單的要求,我們可以在運行時配置委託目標。另外,委託也支持多播,在.NET中,我們應該使用委託的方式來實現回調。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章