2008-09-16 18 views
20

C# 'da, yönetilmeyen kaynakların deterministik olarak temizlenmesi istiyorsanız, "using" anahtar sözcüğünü kullanabilirim. Ama birden fazla bağımlı nesneler için, bu daha fazla ve daha iç içe biter:İç içe geçmiş "kullanma" lardan daha iyi bir deterministik imha modeli var mı?

using (FileStream fs = new FileStream("c:\file.txt", FileMode.Open)) 
{ 
    using (BufferedStream bs = new BufferedStream(fs)) 
    { 
     using (StreamReader sr = new StreamReader(bs)) 
     { 
      // use sr, and have everything cleaned up when done. 
     } 
    } 
} 

C++, ben böyle yapmak için yıkıcı kullanabilme alışkınım:

{  
    FileStream fs("c:\file.txt", FileMode.Open); 
    BufferedStream bs(fs); 
    StreamReader sr(bs); 
    // use sr, and have everything cleaned up when done. 
} 

orada mı Bunu yapmak için C# daha iyi bir yol? Yoksa çoklu yuvalanma seviyelerine mi takıldım?

cevap

40

:

using (FileStream fs = new FileStream("c:\file.txt", FileMode.Open)) 
using (BufferedStream bs = new BufferedStream(fs)) 
using (StreamReader sr = new StreamReader(bs)) 
{ 
    // all three get disposed when you're done 
} 
+12

Bu tıpkı yuvalanmış gibi - her bir ardışık kullanım tek satırlık kod bloğu olarak ele alınır - bir if ifadesini düşünün, sans {}. Burada kazandığınız tek şey, SEKME tuşuna basmaktan kaçınmak. –

+1

Greg Hurlman ile aynı fikirdeyim, bu bir formatlama hilesidir: sanki, vs, 'using' tek bir deyimi kontrol eder, ama normalde bunu bir deyim bloğuyla kullanırsınız. –

+4

Evet, bu bir biçimlendirme hilesidir, ancak asıl önemli olan nokta, C# 'ya yeni birisi için yararlı olmayan bir yardımcıdır. – Eclipse

-1

kullanarak deyimi dönüşür sözdizimsel şeker:

Açıkça senin nesneler üzerinde Dispose çağırabilir, ancak, güvenli olmayacaktır bunlardan biri istisna, kaynaklar atarsa ​​beri düzgün bir şekilde serbest bırakılmayacak.

+0

NOT: Yanlış. Nesne başlatma, birden fazla nesne olsa bile, deneyin DIŞINDA gerçekleşir. kullanarak (X a = f(), b = f()) {g (a, b);} X a = f() ile aynıdır; Xb = f(); deneyin {g (a, b); } sonunda {b.Dispose(); a.Dispose(); İstisna güvenliği için bir fark var. – Aaron

1

İfadeleri kullanarak yerleştirmek yerine, Elle ayırma çağrılarını el ile yazabilirsiniz, ancak bir noktada neredeyse bir tanesini kesinlikle kaçırırsınız.

Ya FocCop'u veya başka bir tanıtıcı uygulama türü örneğinin bir .Dispose() çağrısına sahip olduğundan veya yuvalama ile uğraştığından emin olun. Birden usings ile iç içe gerekmez

3
Şunları kullanabilirsiniz

Bu sözdizimi bazı şeyleri yoğunlaştırmak için:

using (FileStream fs = new FileStream("c:\file.txt", FileMode.Open)) 
using (BufferedStream bs = new BufferedStream(fs)) 
using (StreamReader sr = new StreamReader(bs)) 
{ 
} 

Bu, tüm bloklar için {} kullanılmamasının IMHO anlamına geldiği nadir durumlardan biridir.

0

sizin gibi, kıvırcık parantez atlayabilirsiniz:

using (FileStream fs = new FileStream("c:\file.txt", FileMode.Open)) 
using (BufferedStream bs = new BufferedStream(fs)) 
using (StreamReader sr = new StreamReader(bs)) 
{ 
     // use sr, and have everything cleaned up when done. 
} 

veya normal deneyin sonunda yaklaşım kullanmalı: Bu çok daha büyük bir net için artı kod satırlarında yapar

FileStream fs = new FileStream("c:\file.txt", FileMode.Open); 
BufferedStream bs = new BufferedStream(fs); 
StreamReader sr = new StreamReader(bs); 
try 
{ 
     // use sr, and have everything cleaned up when done. 
}finally{ 
    sr.Close(); // should be enough since you hand control to the reader 
} 
0

ama okunabilirliği somut kazancı: streamwrapper burada tanımlanır

using (StreamWrapper wrapper = new StreamWrapper("c:\file.txt", FileMode.Open)) 
{ 
    // do stuff using wrapper.Reader 
} 

:

private class StreamWrapper : IDisposable 
{ 
    private readonly FileStream fs; 
    private readonly BufferedStream bs; 
    private readonly StreamReader sr; 

    public StreamWrapper(string fileName, FileMode mode) 
    { 
     fs = new FileStream(fileName, mode); 
     bs = new BufferedStream(fs); 
     sr = new StreamReader(bs); 
    } 

    public StreamReader Reader 
    { 
     get { return sr; } 
    } 

    public void Dispose() 
    { 
     sr.Dispose(); 
     bs.Dispose(); 
     fs.Dispose(); 
    } 
} 

Biraz çaba ile StreamWrapper daha genel ve yeniden kullanılabilir hale getirilebilir.

1

Ben Michael Meadows 'ler gibi daha önce çözümleri uygulamış, ancak üye değişkenlerine denilen Dispose() yöntemler ya da bu sebepten için bir istisna eğer onun StreamWrapper kod sonraki Dispose() es denilen olmayacak dikkate almaz ve kaynaklar sallanabiliyordu.işe o biri için daha güvenli yoludur:

 var exceptions = new List<Exception>(); 

     try 
     { 
      this.sr.Dispose(); 
     } 
     catch (Exception ex) 
     { 
      exceptions.Add(ex); 
     } 

     try 
     { 
      this.bs.Dispose(); 
     } 
     catch (Exception ex) 
     { 
      exceptions.Add(ex); 
     } 

     try 
     { 
      this.fs.Dispose(); 
     } 
     catch (Exception ex) 
     { 
      exceptions.Add(ex); 
     } 

     if (exceptions.Count > 0) 
     { 
      throw new AggregateException(exceptions); 
     } 
    } 
+0

InnerException salt okunur bir özelliktir. Yazmayı nasıl başarabilirsin? – supercat

0

Başka akışı kapalı tabanlı genellikle zaman akışı oluşturarak yeni akım, So içinde geçirilen bir kapanacak daha da örnek azaltmak için belirtmek gerekir.

bir dosya adında 1.xml c: Bu örnek için

using (Stream Reader sr = new StreamReader(new BufferedStream(new FileStream("c:\file.txt", FileMode.Open)))) 
{ 
    // all three get disposed when you're done 
} 
+2

NOT: özel durum güvenliği FAIL. Bu, BufferedStream yapıcısı başarısız olursa, FileStream'yi kapatmaz. sözdizimi kullanmak gerçekten zor olur C++ RAII. – Aaron

0

bize sahip varsayalım

çok hatlı özelliklere sahip textBox1 adında bir metin kutusu, \ ayarlanmış. Not: Hatalı: Yanlış:

const string fname = @"c:\1.xml"; 

StreamReader sr=new StreamReader(new BufferedStream(new FileStream(fname,FileMode.Open,FileAccess.Read,FileShare.Delete))); 
textBox1.Text = sr.ReadToEnd(); 
+0

Hayır, bunu yapamazsınız - eğer BufferedStream veya StreamReader, yapım sırasında bir istisna atarsa, FileStream, GC temizlemeye başlayana kadar atılmayacaktır. Bu şekilde yüzen dosya tutamaçlarını bırakmak istemezsiniz. – Eclipse

İlgili konular