2009-12-21 13 views
7

öncelikle dizeleri IEnumerable üzerinde yineleme bitirdiğinizde zaman "temizleme" yürütür göstermektedir aşağıdaki kodu düşünün. İkinci geçiş, bana acı çeken şey. Sonuna ulaşmadan önce IEnumerable'ı terk etmem ve daha sonra temiz kodun çalıştırılmasını istiyorum. Fakat bunu çalıştırırsanız, ikinci geçişte temizliğin asla yanmayacağını göreceksiniz.Bir IEnumerator'u sonuna kadar yinelemeden nasıl iptal edebilirim?

böyle bir IEnumerable terk tercih edilen yöntem nedir?

static void Main(string[] args) 
{ 
    // first pass 
    foreach (String color in readColors()) 
     Console.WriteLine(color); 

    // second pass 
    IEnumerator<string> reader = readColors().GetEnumerator(); 
    if (reader.MoveNext()) 
    { 
     Console.WriteLine(reader.Current); 
     reader.Dispose(); 
    } 
} 
static IEnumerable<string> readColors() 
{ 
    string[] colors = { "red", "green", "blue" }; 
    for (int i = 0; i < colors.Length; i++) 
     yield return colors[i]; 

    Console.WriteLine("Cleanup goes here"); 
} 
+1

şey eksik olabilir veya örnek aşırı basitleştirilmiş ... ama ne temizleme sen readColors içinde Numaralama sonunda çalıştırmak ened mı? GC'nin işleri iyi halletmesi gerektiği gibi görünüyor. –

+0

Özel bir koleksiyona sahipseniz, aynı zamanda kimlik bilgilerini de uygulayabilirsiniz?!. – serhio

cevap

7

Sen ile bir try..finally içine yineleyici yönteminin ana parçası koymak gerekir:

using (IEnumerator<string> reader = readColors().GetEnumerator()) { 
    reader.MoveNext(); 
    Console.WriteLine(reader.Current); 
} 

temizleme kodunu zorlama gelince sen aşağıdakileri yapabilirsiniz yürütmek zorunda nihayet temizleme kodu:

public IEnumerable<string> readColors() 
    { 
     try 
     { 
      string[] colors = { "red", "green", "blue" }; 
      for (int i = 0; i < colors.Length; i++) 
       yield return colors[i]; 
     } 
     finally 
     { 
      Console.WriteLine("Cleanup goes here"); 
     } 
    } 

kaputun altında bir yineleyici yöntemi IEnumerable veuygular oluşturulacak ayrı bir sınıf, neden olduğunu hatırlayın 210. Temizlemenizi son olarak bloke ederek, oluşturulan sınıf 'Dispose yönteminde biter.

[Düzenleme: (diğer yanıtlar belirttiği gibi) elle Dispose arayarak senin yaklaşım üzerinde using deyimi tercih. Tartışmayı düşündüğümüzü bu şekilde yaptığınızı düşünüyordum, ama yine de işaret etmekte fayda var.]

+0

@Luke: Evet öyle. Bu, 'readerDispose(); 'satırı. – jason

+0

Doğru cevap bu, bunu yaptıktan sonra, şu anda sahip olduğunuz karmaşık koddan ziyade "foreach" kullanmaya devam etmek için ikinci satırınızı basitleştirebilirsiniz. Sadece yapın: foreach (readColors() öğesinde dize rengi {Console.WriteLine (color); break; } – StarPacker

4

Bu, onu terk etmenin bir yolu. döngü for (int i = 0; i < colors.Length; i++) asla tamamlanıncaya kadar devam eder çünkü

Cleanup goes here 

konsolda baskılı göremiyoruz nedenidir. Temizleme kodunun yürütülmesi için zorlamak için aşağıya bakın.

Burada başka bir yolu. Bu C# IDisposable nesneleri kullanmak için tercih edilen modeldir. Bu, bir istisna meydana gelse bile IEnumerator.Dispose çağrılmasına neden olacağından tercih edilir.

static IEnumerable<string> readColors() { 
    string[] colors = { "red", "green", "blue" }; 
    try { 
     for (int i = 0; i < colors.Length; i++) { 
      yield return colors[i]; 
     } 
    } 
    finally { 
     Console.WriteLine("Cleanup goes here"); 
    } 
} 
+0

@Downvoter: Bir neden ver. Ben downvote verdiğinde – jason

+0

, çok mantıklı görünmüyordu cevap hatlarının sadece bir çift vardı. Şimdi açıkladın, kaldırdım. –

+0

@Rob Levine: Biraz erken o kadar adil bir şekilde göndermiştim. Yorum yapmak için geri döndüğünüz için teşekkür ederiz. – jason

1

Temizleme yapmayı tercih etmenin, IDisposable kullanarak olduğunu düşünüyorum. Bu durumda, belirli bir IEnumerator<string> ile IEnumerable<string> kendi uygulanmasının daha iyi ve normal Dispose yöntemi kullanılarak. Sen foreach kullanırken ücretsiz için elden olsun.

class MyEnumerator : IEnumerator<string> 
    { 
     // ... 
     #region IDisposable Members 

     public void Dispose() 
     { 
      // do your cleanup here 
      throw new NotImplementedException(); 
     } 

     #endregion 
     // ... 
    } 
+0

Neden düşüş var? –

+1

Kendiniz uygulamanız gerekmez - temizleyiciyi son olarak bloke ettiğiniz sürece derleyici sizin için yapar. –

+0

Muhtemelen doğru ve basit durumlar için cevabınızın daha iyi olduğunu düşünüyorum. –

0
try { 

    string[] colors = { "red", "green", "blue" }; 
    for (int i = 0; i < colors.Length; i++) { 
    if(condition == true) 
     break; 
    yield return colors[i]; 
    } 
} 
finally { 
    Console.WriteLine("Cleanup goes here"); 
} 
+0

@Luke: Evet öyleyse. Bu, 'readerDispose(); 'satırı. – jason

İlgili konular