乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      閉包和對象的關(guān)系

       quasiceo 2016-07-17

      閉包和對象的關(guān)系

      下面的這段C#3.0代碼看似再普通不過:

      Stack stack = StackFactory.New();
      stack.Push(1);
      stack.Push(2);
      stack.Push(3);
      Console.WriteLine(stack.Pop());
      Console.WriteLine(stack.Pop());
      Console.WriteLine(stack.Pop());

      運(yùn)行結(jié)果:

      >>3

      >>2

      >>1

      但如果我告訴你Stack并不是一個普通的class Stack,而是一個類型別名:using Stack = System.Func<T1, R1>,它其實(shí)是一個委托,你會不會覺得很神奇?說得更清楚一些,StackFatory.New()所創(chuàng)建的不是一個普通對象,而是創(chuàng)建了一個閉包(Closure)。

       

      閉包是什么?

      那么閉包究竟是什么呢?目前有兩種流行的說法:一種說法是閉包是在其詞法上下文中引用了自由變量的函數(shù);另一種說法認(rèn)為閉包是由函數(shù)和與其相關(guān)的引用環(huán)境組合而成的實(shí)體。兩種說法都對,但我更傾向于第二種表述,因?yàn)樗鞔_地將閉包定義為“實(shí)體”。從例子中我們可以看出,閉包可以表現(xiàn)出對象的特征,而普通的lambda函數(shù)或delegate更像是某個方法。結(jié)合兩種定義,我認(rèn)為可以把閉包理解為帶狀態(tài)的函數(shù)。

       

      自由變量

      我們先來看一個閉包的簡單例子:

      static Func<int, int> AddX(int x) {
          return (y) => x + y;
      }

      這里的lambda函數(shù)(y) => x + y就是一個閉包,它引用了其詞法上下文之外的自由變量x。對AddX(8)求值將用8代換x,即(y)=>8 + y;若再繼續(xù)求值A(chǔ)ddX(8)(100)將得到8 + 100 = 108。

       

      狀態(tài)

      下面我們將看到如何使閉包具有狀態(tài):

      static Func<int> NewCounter() {
          int x = 0;
          return () => ++x;
      }

      Func<int> counter1 = NewCounter();
      Console.WriteLine(counter1());
      Console.WriteLine(counter1());
      Console.WriteLine(counter1());

      Func<int> counter2 = NewCounter();
      Console.WriteLine(counter2());
      Console.WriteLine(counter2());
      Console.WriteLine(counter2());

      運(yùn)行結(jié)果:

      >>1

      >>2

      >>3

      >>1

      >>2

      >>3

      我們通過NewCounter創(chuàng)建了一個閉包,每次對閉包進(jìn)行求值都會使其環(huán)境的局部變量x增1,這樣就體現(xiàn)了閉包的狀態(tài)。同時,我們注意到局部變量x對于不同的閉包是獨(dú)立的,counter1和counter2并不共享同一個x。

       

      閉包 vs class

      這里我們可以和OOP程序做一個對比,如果要用類來實(shí)現(xiàn)Counter我們會怎么做呢?

      class Counter{ //對應(yīng)NewCounter

          private int x; //對應(yīng)局部變量int x

          public Counter() { x = 0; } //new Counter()對應(yīng)NewCounter()

          public int Count() { return ++x;} //對應(yīng)() => ++x

      }

      和 上面的閉包程序相比,從結(jié)構(gòu)上看是不是有些類似呢?Counter類與NewCounter函數(shù)對應(yīng);new Counter()與NewCounter()對應(yīng);Counter類的私有成員x和NewCounter的局部變量x對應(yīng);Counter類的 Count()方法與閉包對應(yīng)。

       

      行為

      除了狀態(tài),我們還需要讓閉包具備類似stack.Push()和stack.Pop()這樣的對象行為。由于閉包只擁有一個()運(yùn)算符,需要怎樣做才能使其具有多個方法呢?答案是高階函數(shù)(Higher-Order Function)??磩偛臩tack的例子:

      public enum Method {
          Push, Pop, Top
      }

      public static Func<Method, object> NewStack() {
          LinkedList<int> aList = new LinkedList<int>();
          Func<Method, object> func = (method) => {
              switch (method) {
                  case Method.Push:
                      Action<int> push = (int aValue) => { aList.AddLast(aValue); };
                      return push;
                  case Method.Pop:
                      Func<int> pop = () => {
                          int value = aList.Last.Value;
                          aList.RemoveLast();
                          return value;
                      };
                      return pop;
                  case Method.Top:
                      Func<int> top = () => { return aList.Last.Value; };
                      return top;
                  default:
                      return null;
              }
          };
          return func;
      }

      NewStack()返回的是一個Func<Method, object>類型的閉包,它的參數(shù)是enum Method類型的,返回值是object。NewStack()(Method.Push)將得到:

      Action<int> push = (int aValue) => { aList.AddLast(aValue); };

       

      這就是實(shí)際的Push方法!不過,在調(diào)用之前還需要顯式轉(zhuǎn)換一下類型:

      (NewStack()(Method.Push) as Action<int>)(1);

       

      最后,我們利用C#3.0的擴(kuò)展方法(Extension Method)包裝一下,讓這個調(diào)用更加簡潔:

      public static void Push(this Func<Method, object> aStack, int aValue){
          (aStack(Method.Push) as Action<int>)(aValue);
      }

      public static int Pop(this Func<Method, object> aStack){
          return (int)(aStack(Method.Pop) as Func<int>)();
      }

      public static int Top(this Func<Method, object> aStack){
          return (int)(aStack(Method.Top) as Func<int>)();
      }

       

      這樣,我們就能寫出stack.Push(1), stack.Pop()這樣很OO的代碼來了!通過這樣一步步地探索,不知道您是否對函數(shù)式編程的閉包以及它和OOP對象的關(guān)系有了更深的理解呢?

       

      模式

      我們可以把上面在C#3.0中用閉包創(chuàng)建對象的方法歸納為一種固定的模式,不妨稱其為閉包工廠模式(Closure Factory Pattern)。模式要點(diǎn)包括:

      1. 定義一個工廠類XXFactory,提供創(chuàng)建閉包對象的靜態(tài)工廠方法New;

      2. 在New方法的內(nèi)定義局部對象作為閉包對象的狀態(tài)m_States;

      3. 定義enum Method表示對象所具有的方法;

      4. 在New方法內(nèi)創(chuàng)建并返回一個引用m_States的閉包c(diǎn)losureObject,其類型為Func<Method, object>;

      5. closureObject接受Method參數(shù),返回表示該方法的閉包(或普通委托)的methodObject;

      6. 通過擴(kuò)展方法為Func<Method, object>定義擴(kuò)展方法,為closureObject的方法調(diào)用加上語法糖衣。

       

      參考

      閉包的概念、形式與應(yīng)用

      The Beauty of Closures

      posted on 2010-11-01 08:56 Todd Wei 閱讀(3824) 評論(13) 編輯 收藏

      評論

      #1樓 2010-11-01 09:01 顧曉北  

      閉包?
        回復(fù)引用

      #2樓 2010-11-01 09:23 沒一句正經(jīng)的業(yè)余程序員  

      “一種說法是閉包是在其詞法上下文中引用了自由變量的函數(shù)”,這是從語法角度講。
      ”另一種說法認(rèn)為閉包是由函數(shù)和與其相關(guān)的引用環(huán)境組合而成的實(shí)體”,這是從語義角度講,實(shí)際編譯器實(shí)現(xiàn)可能未必如此。
      和lisp、javascript等動態(tài)語言的實(shí)現(xiàn)相比,c#的閉包示例顯得好繁瑣。

        回復(fù)引用

      #3樓[樓主] 2010-11-01 09:31 Todd Wei  

      @ fzwudc
      >>lisp、javascript等動態(tài)語言的實(shí)現(xiàn)相比,c#的閉包示例顯得好繁瑣
      是的,C#的lambda需要進(jìn)行類型檢查而不是符號演算。
        回復(fù)引用

      #4樓 2010-11-01 12:48 諾貝爾  

      對閉包這個名字感到無語的人飄過
        回復(fù)引用

      #5樓 2010-11-02 03:59 Ivony...  

      其實(shí),沒看出實(shí)用價值。

      不過利用閉包來模擬成員變量,倒并不是新鮮玩意兒,JavaScript就是利用閉包來實(shí)現(xiàn)私有成員的。

      的確很好玩。
        回復(fù)引用

      #6樓 2010-11-02 08:14 空逸云  

      引用一種說法是閉包是在其詞法上下文中引用了自由變量的函數(shù);另一種說法認(rèn)為閉包是由函數(shù)和與其相關(guān)的引用環(huán)境組合而成的實(shí)體。兩種說法都對,但我更傾向于第二種表述

      相比較于LZ.我更傾向于第一種.原因其實(shí)就是你在使用Lambda/LINQ表達(dá)式的時候.調(diào)用到"外部"的變量.編譯器的生成代碼其實(shí)是生成一個"閉包"的class.這是我所理解的閉包.而且閉包帶來的還有就是你的變量的"域"的延長.
      http://www.cnblogs.com/kongyiyun/archive/2010/10/15/1851866.html
        回復(fù)引用

      #7樓 2010-11-02 17:23 虛假真人  

      雖然沒完全明白這樣做比起類有什么好處,不過非常精彩!
        回復(fù)引用

      #8樓[樓主] 2010-11-02 18:05 Todd Wei  

      @ 虛假真人
      閉包是FP中實(shí)現(xiàn)OOP的重要手段,所以,個人認(rèn)為閉包在FP語言中的意義大于在OOP語言中。在C#中閉包可以簡化delegate的創(chuàng)建(否則就只能定義class,然后再創(chuàng)建delegate),更易于使用函數(shù)式風(fēng)格編程,這樣更易于把各個模塊粘合起來。本文主要是揭示閉包和對象之間的聯(lián)系。
        回復(fù)引用

      #9樓 2010-11-02 18:23 Albert Yann  

      ╮(╯▽╰)╭閉包,這概念從函數(shù)式過來的吧?
        回復(fù)引用

      #10樓 2010-11-03 13:11 Ivony...  

      引用Todd Wei:
      @虛假真人
      閉包是FP中實(shí)現(xiàn)OOP的重要手段,所以,個人認(rèn)為閉包在FP語言中的意義大于在OOP語言中。在C#中閉包可以簡化delegate的創(chuàng)建(否則就只能定義class,然后再創(chuàng)建delegate),更易于使用函數(shù)式風(fēng)格編程,這樣更易于把各個模塊粘合起來。本文主要是揭示閉包和對象之間的聯(lián)系。



      在純粹函數(shù)式語言中,由于所有變量都是“不可變”的,閉包即使能捕獲到外界變量,但也只是等于多了幾個參數(shù),換言之并不能修改外部變量的值,是不能實(shí)現(xiàn)OOP的。
        回復(fù)引用

      #11樓[樓主] 2010-11-03 13:29 Todd Wei  

      @ Ivony...
      是的,純函數(shù)式中的符號都是引用透明的值語義,沒法實(shí)現(xiàn)引用語義。stack.Push(1)之后和原來的stack在值語義下是不相等的。所以,如果要在純函數(shù)式下實(shí)現(xiàn)stack,寫出來只能是類似這個樣子:
      Pop(Push(Push(New(),1), 2))
        回復(fù)引用

      #12樓 2011-03-06 21:49 egmkang  

      我寫過lua的閉包,這個C#的閉包確是太繁瑣了
        回復(fù)引用

      #13樓[樓主] 2011-06-11 13:24 Todd Wei  

      @ egmkang
      沒看出來Lua的閉包比C#簡單呢?

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多