bir kullanma bloğunun ortasında dönen


196

Gibi bir şey:

using (IDisposable disposable = GetSomeDisposable())
{
    //.....
    //......
    return Stg();
}

Bir iade beyanı için uygun bir yer olmadığına inanıyorum, değil mi?

Yanıtlar:


194

Bazılarının genel olarak işaret ettiği gibi, bu bir sorun değildir.

Sorunlara neden olacak tek durum, bir using ifadesinin ortasına dönüp ek olarak in using değişkenini döndürmenizdir. Ama sonra tekrar, geri dönmediyseniz ve bir değişkene bir referans tuttuğunuzda bile sorunlara neden olur.

using ( var x = new Something() ) { 
  // not a good idea
  return x;
}

Tıpkı kötü

Something y;
using ( var x = new Something() ) {
  y = x;
}

1
Bahsettiğim nokta hakkındaki sorumu düzenlemek üzereydim. Teşekkürler.
tafa

Lütfen bunun neden kötü olduğunu anlamama yardımcı ol. Bir yardımcı işlevde kullandığım bir akışı görüntü işleme için başka bir işleve döndürmek istiyorum. Bunu yaparsam Akış bertaraf edilecek gibi görünüyor?
John Shedletsky

3
@JohnShedletsky Bu durumda işlev çağrınızın kullanımı ile sarılmalıdır. (Stream x = FuncToReturnStream ()) {...} kullanarak ve FuncToReturnStream içinde kullanmamak gibi.
Felix Keil

@JohnShedletsky Eminim çünkü returndeyim usingbloğun sonuna herhangi bir kod yolu ile erişilemez olur. usingGerekirse nesnenin atılabilmesi için bloğun ucunun çalıştırılması gerekir.
facepalm42

147

Tamamen iyi.

Görünüşe göre bunu düşünüyorsun

using (IDisposable disposable = GetSomeDisposable())
{
    //.....
    //......
    return Stg();
}

körü körüne çevrildi:

IDisposable disposable = GetSomeDisposable()
//.....
//......
return Stg();
disposable.Dispose();

Ki, kuşkusuz, bir sorun olacağını ve yapacak usingişte bu yüzden hangi --- deyimi oldukça anlamsız değil ne yaptığını.

Derleyici, bloktan nasıl ayrılacağından bağımsız olarak, kontrol bloktan ayrılmadan önce nesnenin atılmasını sağlar.


7
Görünüşe göre öyleydim.
tafa

Büyük cevap @ James Curran! Ama ne tercüme edildiğini oldukça meraklandırıyor. Yoksa bu sadece IL'de ifade edilebilir mi? (daha önce hiç okumamı denemedim).
Bart

1
@Bart - Dönüş ifadesini geçici bir değişkene değerlendirmek, sonra dispose yapmak, sonra geçici değişkeni döndürmek olarak düşünüyorum.
ToolmakerSteve

@James Curran. Yukarıdan buraya, Arka planda ne olduğunu sadece siz açıkladınız. Çok teşekkürler.
Sercan Timoçin

@Bart muhtemelen çevrildi: {... kodunuzu ...} deneyin {x.Dispose (); }
Bip901

94

Kesinlikle iyi - hiç sorun değil. Neden yanlış olduğuna inanıyorsun?

Kullanım ifadesi, bir try / nihayet bloğu için sadece sözdizimsel şekerdir ve Grzenio'nun dediği gibi bir try bloğundan geri dönmenin iyi olduğunu.

Dönüş ifadesi değerlendirilir, son olarak blok yürütülür, sonra yöntem geri döner.


5
James Curran'ın cevabı ne düşündüğümü açıklıyor.
tafa

27

Bu mükemmel bir şekilde çalışacaktır, tıpkı try{}finally{}


18

Bu tamamen kabul edilebilir. Bir kullanarak deyim ıdisposable nesne ne olursa olsun bertaraf edilecektir sağlar.

Gönderen MSDN :

Using ifadesi, nesne üzerindeki yöntemleri çağırırken özel durum oluşsa bile Dispose'in çağrılmasını sağlar. Aynı sonucu, nesneyi bir try bloğunun içine koyarak ve sonunda bir blokta Dispose (Çağır) olarak çağırarak da elde edebilirsiniz; aslında, using ifadesi derleyici tarafından bu şekilde çevrilir.


14

Feryat kodu nasıl usingçalıştığını gösterir :

private class TestClass : IDisposable
{
   private readonly string id;

   public TestClass(string id)
   {
      Console.WriteLine("'{0}' is created.", id);
      this.id = id;
   }

   public void Dispose()
   {
      Console.WriteLine("'{0}' is disposed.", id);
   }

   public override string ToString()
   {
      return id;
   }
}

private static TestClass TestUsingClose()
{
   using (var t1 = new TestClass("t1"))
   {
      using (var t2 = new TestClass("t2"))
      {
         using (var t3 = new TestClass("t3"))
         {
            return new TestClass(String.Format("Created from {0}, {1}, {2}", t1, t2, t3));
         }
      }
   }
}

[TestMethod]
public void Test()
{
   Assert.AreEqual("Created from t1, t2, t3", TestUsingClose().ToString());
}

Çıktı:

't1' oluşturulur.
't2' oluşturulur.
't3' oluşturulur.
'T1, t2, t3'ten yaratıldı' oluşturulur.
't3' atılmıştır.
't2' atılmıştır.
't1' atılır.

İmha edilenler return ifadesinden sonra ancak işlevin çıkışından önce çağrılır.


1
Bazı C # nesnelerinin özel bir şekilde kullanıldığını lütfen unutmayın, örneğin, WCF istemcileri yukarıdaki dönüş "atılan nesneye erişemiyor" gibi bir kullanım ifadesidir
OzBob

-4

Belki de bunun kabul edilebilir olduğu% 100 doğru değil ...

Kullanıcıları iç içe geçiriyor ve iç içe geçmişten geri dönüyorsanız, güvenli olmayabilir.

Bunu örnek olarak alalım:

using (var memoryStream = new MemoryStream())
{
    using (var textwriter = new StreamWriter(memoryStream))
    {
        using (var csv = new CsvWriter(textwriter))
        {
            //..write some stuff to the stream using the CsvWriter
            return memoryStream.ToArray();
        }
    }
}

Ben csv olarak çıktı için bir DataTable geçiriyordu. Ortadaki dönüşle, tüm satırları akışa yazıyordu, ancak çıktılanan csv'de her zaman bir satır eksikti (veya arabellek boyutuna bağlı olarak). Bu bana bir şeyin düzgün bir şekilde kapatılmadığını söyledi.

Doğru yol, önceki tüm kullanıcıların doğru bir şekilde atıldığından emin olmaktır:

using (var memoryStream = new MemoryStream())
{
    using (var textwriter = new StreamWriter(memoryStream))
    {
        using (var csv = new CsvWriter(textwriter))
        {
            //..write some stuff to the stream using the CsvWriter
        }
    }

    return memoryStream.ToArray();
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.