C#-continuation-passing style(CPS)

來源:互聯網
上載者:User

如果你還不是很瞭解CPS是什麼,那麼推薦幾個連結給你(希望你的英語要給力啊):

http://blogs.msdn.com/b/wesdyer/archive/2007/12/22/continuation-passing-style.aspx

http://en.wikipedia.org/wiki/Continuation-passing_style

http://blogs.msdn.com/b/ericlippert/archive/2010/10/22/continuation-passing-style-revisited-part-two-handwaving-about-control-flow.aspx

 

CPS(continuation-passing style):字面可以理解為後繼式傳遞格式,這是在函數式編程中的一個特性。但在C#中Lambda運算式和Action<T> 泛型委派結合起來,能夠很好地實現這一特性。

 

原來我們用結構化處理異常的方式:

void Q()
{
  try
  {
    B(A());
  }
  catch
  {
    C();
  }
  D();
}

int A(int a)
{
    throw;
    return 0; // 不可達,暫時忽略

}
void B(int x) { //to do something }
void C() { //to do something  }
void D() { //to do something  }

 

這些方法調用是否物件導向,這不是我們要討論的話題。但是不管怎麼說,try{...}catch{...}finally{...}這種結構化的異常處理方式,至今還是在被廣泛使用。

 

結構化的一個特點,耦合性強,關聯度高。就像流水線一樣緊密結合。

讓我們先看一下,這個調用流程:

首先執行方法A,如果A的調用未產生任何異常,則返回結果給B作為參數,調用B方法,如果方法B執行正常。則方法C不會被執行,直接跳到方法D開始執行。

如果方法A或B任何一方產生異常,執行將會被中止。調用將會跳轉到方法C執行(當然前提是,該異常能被順利捕獲到)。最後再調用方法D。

 

其實CLR在採用結構化的異常處理機制時,實現了一些帥選器和處理器等內部和語言機制,可參考《CLR Via C# 3.0》。但是,既然我們說這種異常處理方式是一種環環相扣的,類似於流式的,為什麼我們不能類比採用CPS來實現呢?

對於ABCD四個方法,我們都考慮兩種情況(其實就是一種if ...else....結構)一種情況:方法調用成功;一種情況方法調用失敗。

於是,可以這樣定義:

Action<T>:接受一個類型為T的參數,並且沒有傳回值;

void A(Action<int> normal, Action error);

void B(int x, Action normal, Action error) { whatever }
void C(Action normal, Action error) { whatever }
void D(Action normal, Action error) { whatever }

註:所有的normal,都可以想象為,我們通常不考慮異常的方法體,所有的error都可以認為對原方法體中出現異常的處理方法

 

這樣對try塊的處理邏輯抽象為:

Try (
       /* tryBody      */ (bodyNormal, bodyError)=>A(
       /* normal for A */   x=>B(x, bodyNormal, bodyError),
       /* error for A  */   bodyError),
       /* catchBody    */ C,
       /* outerNormal  */ ()=>D(qNormal, qError),
       /* outerError   */ qError );
首先,從外部來看try塊只能有兩個出口:

由try——>outerNormal,將執行:()=>D(qNormal, qError)  用outerNormal

try——>catchBody 將執行:()=>C(outerNormal,outerError)即為::()=>C(()=>D(qNormal, qError),outerError)

而對於try體,則有:(bodyNormal, bodyError)=>A(x=>B(x, bodyNormal, bodyError), bodyError);

因此,展開就為:

 

 

 

A(
  x=>B(               // A's normal continuation
    x,                   // B's argument
    ()=>D(            // B's normal continuation
      qNormal,        // D's normal continuation
      qError),        // D's error continuation
    ()=>C(            // B's error continuation
      ()=>D(          // C's normal continuation
        qNormal,      // D's normal continuation
        qError),      // D's error continuation
      qError)),       // C's error continuation
  ()=>C(              // A's error continuation
    ()=>D(            // C's normal continuation
      qNormal,        // D's normal continuation
      qError),        // D's error continuation
    qError))          // C's error continuation

 

如果C拋出異常則,continuation立刻被轉入qError執行;

從可讀性上來講這當然不是一種非常好的實現方式。但這是一種思路,我們在編寫一些前後關聯性很強的方法調用時,並且方法調用不是很多時,可以採用這種做法。

 

下面的實現很好地體現了CPS的流式調用(偽遞迴)和資料處理控制權的交接:

實現Factorial:

static void Main(){    Factorial(5, x => Console.WriteLine(x));}static void Factorial(int n, Action<int> k){    if (n == 0)        k(1);    else        Factorial(n - 1, x => k(n * x));}
當然CPS還有一個很有用的特性就是能夠支援非同步回調,在非同步編程中很有用。
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.