2012-02-13 24 views
6

IEnumerable ertelenecek Verim kullanmak zorunda mı?Bir IEnumerable ertelenecek Verim kullanmalıdır

Burada, ertelenmiş yürütme ve verimi anlamamda yardımcı olan test kodu.

//immediate execution 
     public IEnumerable Power(int number, int howManyToShow) 
     { 
      var result = new int[howManyToShow]; 
      result[0] = number; 
      for (int i = 1; i < howManyToShow; i++) 
       result[i] = result[i - 1] * number; 
      return result; 
     } 

     //deferred but eager 
     public IEnumerable PowerYieldEager(int number, int howManyToShow) 
     { 
      var result = new int[howManyToShow]; 
      result[0] = number; 
      for (int i = 1; i < howManyToShow; i++) 
       result[i] = result[i - 1] * number; 

      foreach (var value in result) 
       yield return value; 
     } 

     //deferred and lazy 
     public IEnumerable PowerYieldLazy(int number, int howManyToShow) 
     { 
      int counter = 0; 
      int result = 1; 
      while (counter++ < howManyToShow) 
      { 
       result = result * number; 
       yield return result; 
      } 
     } 

     [Test] 
     public void Power_WhenPass2AndWant8Numbers_ReturnAnEnumerable() 
     { 
      IEnumerable listOfInts = Power(2, 8); 

      foreach (int i in listOfInts) 
       Console.Write("{0} ", i); 
     } 


     [Test] 
     public void PowerYieldEager_WhenPass2AndWant8Numbers_ReturnAnEnumerableOfInts() 
     { 
      //deferred but eager execution 
      IEnumerable listOfInts = PowerYieldEager(2, 8); 

      foreach (int i in listOfInts) 
       Console.Write("{0} ", i); 
     } 


     [Test] 
     public void PowerYield_WhenPass2AndWant8Numbers_ReturnAnEnumerableOfIntsOneAtATime() 
     { 
      //deferred and lazy execution 
      IEnumerable listOfInts = PowerYieldLazy(2, 8); 

      foreach (int i in listOfInts) 
       Console.Write("{0} ", i); 
     } 
+0

Bir clojure sözdizimi kullanabilir veya verimsiz aynı şeyi yapmak için bir nesne yazabilirim. Soruyu tamamen cevaplamak için bir örnek yazmak istemiyorum. –

cevap

6

O yield kullanmak yok yok - sonuçta yield özel enumerator (IEnumerator[<T>]) yazma ve ilk MoveNext() dek harekete geciktirerek, yapar o her şeyi yapabilirsiniz. Ancak, bu uygulamak için oldukça acı verici. (Bir sonra sonra veri erişen diğer bir yöntem kullanır yield kullanmayan biri, - Eğer kullanımını yield yapmak Kesinlikle eğer, uygulama varsayılan olarak ertelenir (bunu iki yöntem kullanılarak olmayan ertelenmiş yapabilirsiniz . yineleyici blok) numaralandırıcıyı uygulamak Açıkçası

, enumerator'ler yazma zordur ve arabası ben kesinlikle gerekli olmadıkça bunu önlemek yineleyici bloklar harikadır

0

olan Ertelendi ve istekli karşıtların -... ertelenen için tembel sadece eş anlamlıdır

İstekli bir dizidir. Bir liste veya dizi gibi ich önceden hesaplanır. Ertelenmiş bir sıra, yinelendiği zaman hesaplanır.

Örneklerinizde, Power, bir dizi hesapladığı ve döndürdüğü için heveslidir. Bu, sonuç IEnumerable yinelenene kadar dizi oluşturmayan PowerYieldEager'dan farklıdır.

Bir ertelenen vs bir dizinin içeriği vs bir sekans için potansiyel olarak istekli düşünebiliriz. Bunu akılda tutarak, yield return sadece ertelemenin bir yoludur; Sonuçlar istendiğinde hesaplanan herhangi bir sekans ertelenmiş bir sekanstır.

+0

Dili açıkladığınız için teşekkürler Bryan –

1

bir fonksiyon IEnumerable bir fonksiyonu F2 ertelenmiş ise, o zaman F1 aşağıdaki kodda, F1 ve F2 her ikisi de, örneğin,

ertelenir (F2) olarak hesaplanan bir IEnumerable dönebilir döner (F1) ertelenmiş

public IEnumerable<int> F2() 
{ 
    for (int i = 0; i < 10; i++) { 
     yield return i; 
    } 
} 

public IEnumerable<int> F1() 
{ 
    return F2(); 
} 
+0

İlginç kenar! –

+0

'F2 ertelenirse, F1 ertelenir ': Bu özel durumda evet, ancak her zaman değil (bkz: http://stackoverflow.com/a/17817359/1443490) – cheesemacfly