程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> .NET實例教程 >> yield,很好很強大

yield,很好很強大

編輯:.NET實例教程
 yield是c#2.0中引入的關鍵詞,以前只是匆匆看過它的用法,覺得不過是個語法糖.這兩天突然對yIEld產生了興趣進行了一些小實驗.有了一些心得放在這裡與大家共享.
   yIEld確實是一塊非常好的語法糖,方便我們寫iterator.比如我要給Tuple加一個迭代功能就非常容易.


//我以Tuple<T1, T2, T3>舉例
public class Tuple<T1, T2, T3> : Tuple<T1, T2>,IEnumerable
...{
       T3 _t3;
        public Tuple(T1 t1, T2 t2, T3 t3) : base(t1, t2)           
        ...{
            this._t3 = t3;
        }
        //很方便的加入迭代功能
        public override IEnumerator GetEnumerator()
        ...{
            yIEld return this.Item_1;
            yIEld return this.Item_2;
            yIEld return this._t3;
        }
}
yIEld return相當於執行了一次MoveNext(); 並返回Current的過程.所以在上面的代碼裡我才能非常容易的給Tuple加上迭代功能.
  yIEld不僅能夠簡化實現迭代功能,它還能幫助我們換種方式實現遞歸.來看看下面這個演示函數它非常容易的實現了一個中序遍歷


IEnumerable<T> ScanInOrder(Node<T> root)
...{
   if(root.LeftNode != null)
   ...{
      foreach(T item in ScanInOrder(root.LeftNode))
      ...{
         yIEld return item;
      }
   }
 
   yIEld return root.Item;
 
   if(root.RightNode != null)
   ...{
      foreach(T item in ScanInOrder(root.RightNode))
      ...{
         yIEld return item;
      }
   }
}
而在我前面的文章中介紹了用尾遞歸的方式計算Fibonacci數列的方法.在這裡我要用yIEld實現一個不同版本.


//使用YIEld計算Fibonacci數列
public long Fib_YIEld(int n)
        ...{
            long num = 0;
            int index = 3;
            foreach (long b in this.YIEld(1, 1))
            ...{
                if (index == n)
                ...{
                    num = b;
                    break;
                }
                else
                    ++index;               
            }
            return num;
        }
        public IEnumerable<long> YIEld(long b1, long b2)
     ...{
            yIEld return b1 + b2;
            foreach (long b in YIEld(b2, b1 + b2))
                yIEld return b;            
        }

這種實現方式和遞歸函數不同的地方就是它沒有終止條件.上面的Yield函數實際上能夠計算一個無限數列(這有點像FP中的惰性計算)而Fib_YIEld函數才是真正實現業務邏輯的地方.這是不是有點業務邏輯和通用算法分離的感覺.再讓我們看一個例子.

  在寫WebForm或WinForm程序的時候我們經常會應用一個技巧就是把業務實體對象(Entity Object)的數據賦值給UI上的控件.所以我們就會寫一個遞歸遍歷所有控件的函數類似於如下函數:



public void SetValue(Control ctl, EntityObject obj)
...{
  foreach(Control c in ctl.Controls)
 ...{
    if(c is TextBox)
    ...{
          //利用反射將obj的數據賦值給該控件
    }
    if(c is CheckBox)
    ...{
          //利用反射將obj的數據賦值給該控件
 }
    //......
   if(c.HasControls())
        SetValue(c, obj);
 }
}
    //GetValue函數與此相仿

而用yIEld就會變成這個樣子(注:關於Tuple的HasType()函數請看這裡)



public IEnumerable<Control> Iterator(Control baseCtl, Tuple t)
        ...{
            foreach(Control c in baseCtl.Controls)
            ...{
                if (!t.HasType(c))
                ...{
                    foreach (Control c1 in Iterator(c, t))
                        yIEld return c1;
                }
                yIEld return c;
            }
        }
public void SetValue(EntityObject obj)
...{
    foreach(Control c in Iterator(this, new Tuple<TextBox, CheckBox, Button>()))
   ...{
          //操作c
   }
}

這樣我就可以把Iterator函數放到基礎庫中,而把對WebForm和WinForm控件的賦值操作放到業務邏輯層中.實現了一定的解耦.

  看來yield還有待挖掘的潛力,特別是它可以把函數中的臨時變量保存到棧上的能力,我覺得可以在多線程編程中應用yield(微軟msdn雜志有一篇介紹應用yIEld實現異步IO的文章大家有興趣可以查一下,具體網址我不記得了不好意思).



  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved