Effective C# 原則21:用委託來表示回調(譯)

來源:互聯網
上載者:User

Effective C# 原則21:用委託來表示回調

Item 21: Express Callbacks with Delegates

我:“兒子,到院子裡除草去,我要看會書。”
斯科特:“爸,我已經打掃過院子了。”
斯科特:“爸,我已經把草放在除草機上了。”
斯科特:“爸,除草機不能啟動了。”
我:“讓我來啟動它。”
斯科特:“爸,我做好了。”

這個簡單的互動展示了回調。我給了我兒子一個任務,並且他可以報告狀態來(重複的)打斷我。而當我在等待他完成任務的每一個部份時,我不用阻塞我自己的進程。他可以在有重要(或者事件)狀態報表時,可以定時的打斷我,或者向我詢求協助。回調就是用於非同步提供伺服器與客戶之間的資訊反饋。它們可能在多線程中,或者可能是簡單的提供一個同步更新點。在C#裡是用委託來表示回調的。

委託提供了一個型別安全的回調定義。儘管委託大多數是為事件使用的,但這不應該是C#語言中唯一使用這一功能的地方。任何時候,如果你想在兩個類之間進行通訊,而你又期望比使用介面有更少的偶合性,那麼委託是你正確的選擇。委託可以讓你在運行確定(回調)目標並且通知使用者。委託就是包含了某些方法的引用。這些方法可以是靜態方法,也可以是執行個體方法。使用委託,你可以在運行時確定與一個或者多個客戶對象進行互動。

多播委託包含了添加在這個委託上的所有單個函數調用。有兩點要注意的:它不是異常安全的,並且傳回值總是委託上最後一個函數調用後返回的值。

在多播委託調用的內部,每一個目標都會成功的調用。委託不會捕獲任何的異常,也就是說,在委託鏈中拋出的任何異常都會終止委託鏈的繼續調用。

在傳回值上也存在一個簡單的問題。你可以定義委託有傳回值或者是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;
  }
}

在單委託上這是工作的,但在多播委託上卻是有問題的:
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;
  }
}

這時,我已經定義好了程式的語義,因此委託鏈上的每個委託必須返回真以後,才能繼續調用。

委託為運行時回調提供了最好的方法,使用者簡單的實現使用者對類的需求。你可以在運行時確定委託的目標。你可以支援多個使用者目標,這樣,使用者的回調就可以用.Net裡的委託實現了。
==================================
   

Item 21: Express Callbacks with Delegates
Me: "Son, go mow the yard. I'm going to read for a while."

Scott: "Dad, I cleaned up the yard."

Scott: "Dad, I put gas in the mower."

Scott: "Dad, the mower won't start."

Me: "I'll start it."

Scott: "Dad, I'm done."

This little exchange illustrates callbacks. I gave my son a task, and he (repeatedly) interrupted me with the status. I did not block my own progress while I waited for him to finish each part of the task. He was able to interrupt me periodically when he had an important (or even unimportant) status to report or needed my assistance. Callbacks are used to provide feedback from a server to a client asynchronously. They might involve multithreading, or they might simply provide an entry point for synchronous updates. Callbacks are expressed using delegates in the C# language.

Delegates provide type-safe callback definitions. Although the most common use of delegates is events, that should not be theonly time you use this language feature. Any time you need to configure the communication between classes and you desire less coupling than you get from interfaces, a delegate is the right choice. Delegates let you configure the target at runtime and notify multiple clients. A delegate is an object that contains a reference to a method. That method can be either a static method or an instance method. Using the delegate, you can communicate with one or many client objects, configured at runtime.

Multicast delegates wrapall the functions that have been added to the delegate in a single function call. Two caveats apply to this construct: It is not safe in the face of exceptions, and the return value will be the return value of the last function invocation.

Inside a multicast delegate invocation, each target is called in succession. The delegate does not catch any exceptions. Therefore, any exception that the target throws ends the delegate invocation chain.

A similar problem exists with return values. You can define delegates that have return types other than void. You could write a callback to check for user aborts:

public delegate bool ContinueProcessing();

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

 

It works as a single delegate, but using it as a multicast is problematic:

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

 

The value returned from invoking the delegate is the return value from the last function in the multicast chain. All other return values are ignored. The return from the CheckWithUser() predicate is ignored.

You address both issues by invoking each delegate target yourself. Each delegate you create contains a list of delegates. To examine the chain yourself and call each one, iterate the invocation list yourself:

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;
  }
}

 

In this case, I've defined the semantics so that each delegate must be true for the iteration to continue.

Delegates provide the best way to utilize callbacks at runtime, with simpler requirements on client classes. You can configure delegate targets at runtime. You can support multiple client targets. Client callbacks should be implemented using delegates in .NET.

 
   

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.