Soru 'using' ifadesi vs 'nihayet dene'


Okuma / yazma kilitlerini kullanacağım bir sürü özellik var. Onları ya try finally ya da using fıkra.

İçinde try finally Önce kilidi alırdım tryve finally. İçinde using fıkra, kurucunun kilidini alan bir sınıf oluşturur ve Dispose yönteminde yayınlar.

Çok fazla yerde okuma / yazma kilitlerini kullanıyorum, bu yüzden daha özlü olabilecek yollar aradım. try finally. Bir yolun neden tavsiye edilmediğine veya neden birinin diğerinden daha iyi olabileceğine dair bazı fikirler duymakla ilgileniyorum.

Yöntem 1 (try finally):

static ReaderWriterLock rwlMyLock_m  = new ReaderWriterLock();
private DateTime dtMyDateTime_m
public DateTime MyDateTime
{
    get
    {
        rwlMyLock_m .AcquireReaderLock(0);
        try
        {
            return dtMyDateTime_m
        }
        finally
        {
            rwlMyLock_m .ReleaseReaderLock();
        }
    }
    set
    {
        rwlMyLock_m .AcquireWriterLock(0);
        try
        {
            dtMyDateTime_m = value;
        }
        finally
        {
            rwlMyLock_m .ReleaseWriterLock();
        }
    }
}

Yöntem 2:

static ReaderWriterLock rwlMyLock_m  = new ReaderWriterLock();
private DateTime dtMyDateTime_m
public DateTime MyDateTime
{
    get
    {
        using (new ReadLock(rwlMyLock_m))
        {
            return dtMyDateTime_m;
        }
    }
    set
    {
        using (new WriteLock(rwlMyLock_m))
        {
            dtMyDateTime_m = value;
        }
    }
}

public class ReadLock : IDisposable
{
    private ReaderWriterLock rwl;
    public ReadLock(ReaderWriterLock rwl)
    {
        this.rwl = rwl;
        rwl.AcquireReaderLock(0);
    }

    public void Dispose()
    {
        rwl.ReleaseReaderLock();
    }
}

public class WriteLock : IDisposable
{
    private ReaderWriterLock rwl;
    public WriteLock(ReaderWriterLock rwl)
    {
        this.rwl = rwl;
        rwl.AcquireWriterLock(0);
    }

    public void Dispose()
    {
        rwl.ReleaseWriterLock();
    }
}

60
2017-11-10 19:31


Menşei




Cevaplar:


MSDN'den Deyimi kullanarak (C # Referans)

Kullanılan deyim, nesne üzerinde yöntemleri çağırırken bir istisna olsa bile Dispose'ın çağrılmasını sağlar. Aynı sonucu, nesneyi bir try bloğunun içine koyarak ve ardından bir son blokta At'ı çağırarak elde edebilirsiniz; Aslında, kullanma ifadesinin derleyici tarafından nasıl dönüştürüldüğü budur. Kod örneği daha önce derleme zamanında aşağıdaki koda genişler (nesne için sınırlı kapsamı oluşturmak için ek küme parantezlerine dikkat edin):

{
  Font font1 = new Font("Arial", 10.0f);
  try
  {
    byte charset = font1.GdiCharSet;
  }
  finally
  {
    if (font1 != null)
      ((IDisposable)font1).Dispose();
  }
}

Yani temel olarak aynı koddur ama güzel otomatik boş kontroller ve değişkeniniz için ekstra kapsam. Dokümantasyon ayrıca "IDisposable nesnenin doğru kullanımını" sağladığını belirtir, böylece gelecekte herhangi bir belirsiz durum için daha iyi bir çerçeve desteği alabilirsiniz.

Yani seçenek 2 ile gidin.

Değişime sahip olmak bir kapsam içinde Artık ihtiyaç duyulmadığı anda biten bu da bir artı.


77
2017-11-10 19:43



deyimi kullanarak veya yeniden kullanıldığında veya param olarak geçirilemeyen bir kaynağı serbest bırakmak için en iyisi nedir? - bjan
Kuzen iyi, neden düşünüyorsun? using bu durumda? bu ne değil using için. - chakrit
bu yüzden de bahsetmiştim try/catchişlemek için tek yol gibi görünüyor try/catch/finally blok. ümit using bunu halledebilir - bjan
İyi evet try/finallyBu durumda tek seçeneğiniz sanırım. Ancak IMO, sanırım her zaman nesnenin ömrünü sürdürmekten sorumlu bir nesne / kod parçası olmalıdır. (Dispose () her zaman çağrılmalıdır.) Eğer bir sınıf sadece bir örneği yönetirse ve bir başkası hatırlamak zorundaysa Onu bertaraf etmek için biraz çeşit kokular olduğunu düşünüyorum. Bunu dil seviyesinde nasıl ekleyeceğinden emin değilim. - chakrit
Sanırım "kullanmama" dan kaçınmanın tek sebebi, tamamen başka bir nesne örneğidir sanırım, tek kullanımdan kaçınmaktır sanırım? - Demetris Leptos


Kesinlikle ikinci yöntemi tercih ederim. Kullanım noktasında daha az, ve daha az hata eğilimli.

İlk durumda, kodu düzenleyen biri, Acquire (Oku | Yaz) Kilitle aramayı ve denemeyi arasına herhangi bir şey eklememeye dikkat etmelidir.

(Bu gibi bireysel özelliklerde bir okuma / yazma kilidini kullanmak genellikle daha fazladır. En iyi seviyede daha iyi uygulanırlar. Basit bir kilit genellikle burada yeterlidir, çünkü kilit tutulduğu zaman çekişme olasılığı çok küçüktür. okuma / yazma kilidini almak ve almak basit bir kilitlemeden daha pahalı bir işlemdir).


11
2017-11-10 19:36



Başarısız olma konusunda ne dersin? Nihayet bir deneme sonunda nihayet bloğu kovacağını biliyorum, imha edilmeyecek herhangi bir yol var mı? - Jeremy
Hayır, kullanım ifadesi esasen deneme / son model için sözdizimsel şekerdir. - Blair Conrad
Kullanan model, nesnenin her zaman bertaraf edilmesini sağlar. - Nathen Silver
Reflektör kullanacak olursanız, kullandığınız bloğun derleyici tarafından bir denemeye dönüştürdüğünü görürsünüz ... nihayet inşa edilir, böylece IL seviyesinde eşdeğerdir. 'Kullanma' sadece sintatik şekerdir. - Rob Walker
^^ nihayet çağrılmayan potansiyel senaryolar olduğunu unutmayın. Örneğin bir elektrik kesintisi. ;) - Quibblesome


Her iki çözümün de kötü olması ihtimalini düşünün. istisnaları maskeliyorlar.

bir try olmadan catch Açıkçası kötü bir fikir olmalı; görmek MSDN neden using Açıklama aynı şekilde tehlikeli.

Not ayrıca Microsoft şimdi önerir ReaderWriterLockSlim ReaderWriterLock yerine.

Son olarak, Microsoft örneklerinin kullanıldığını unutmayın. iki try-catch blokları bu sorunları önlemek için

try
{
    try
    {
         //Reader-writer lock stuff
    }
    finally
    {
         //Release lock
    }
 }
 catch(Exception ex)
 {
    //Do something with exception
 }

Basit, tutarlı, temiz bir çözüm iyi bir hedeftir, ancak sadece kullanamayacağınızı varsayarak lock(this){return mydateetc;}yaklaşımı yeniden düşünebilirsiniz; Daha fazla bilgi ile eminim Stack Overflow yardımcı olabilir ;-)


8
2017-11-10 19:52



Bir denemenin sonunda mutlaka istisnayı maskelemesi gerekmez. Örneğimde, kilit akıtılır, daha sonra kapsam içinde herhangi bir özel durum atılırsa, kilit serbest bırakılır, ancak istisna yine de kabarcıklı olacaktır. - Jeremy
@Jeremy: Eğer sonuncu bloğunuz bir istisna atarsa, try bloğunuzda atılan istisnayı maskeleyecektir - msdn makalesinin söylediği şey sözdizimini kullanarak (aynı) problemdi - Steven A. Lowe
İstisnai maskelemez, istisnayı sizinkiyle aynı şekilde değiştirir. - Jon Hanna


C # "using" ifadesini kişisel olarak mümkün olduğunca sık kullanıyorum, ancak söz konusu potansiyel sorunları önlemek için birlikte yaptığım bazı özel şeyler var. Göstermek için:

void doSomething()
{
    using (CustomResource aResource = new CustomResource())
    {
        using (CustomThingy aThingy = new CustomThingy(aResource))
        {
            doSomething(aThingy);
        }
    }
}

void doSomething(CustomThingy theThingy)
{
    try
    {
        // play with theThingy, which might result in exceptions
    }
    catch (SomeException aException)
    {
        // resolve aException somehow
    }
}

"Using" ifadesini bir yöntemle ve "try" / "catch" bloğuyla başka bir yönteme nesne (ler) in kullanımını ayırdığımı unutmayın. İlgili nesneler için birkaç tane "kullanarak" ifadesini iç içe geçmiş olabilirim (bazen üretim kodumda üç veya dördü geçiyorum).

Benim .. De Dispose() bu özel yöntemler IDisposable sınıfları, istisnaları (ancak hatalar değil) yakalarım ve bunları (Log4net kullanarak) günlüğe kaydederim. Bu istisnaların herhangi birinin işlemimi etkileyebileceği bir durumla karşılaşmadım. Olağan hatalar, her zamanki gibi, çağrı yığınının yayılmasına izin verilir ve genellikle işlemin uygun bir mesajla (hata ve yığın izi) kaydedilmesi sonlandırılır.

Eğer bir şekilde karşılaştığımda önemli bir istisna meydana gelebilirdi. Dispose()Bu durum için yeniden tasarlardım. Açıkçası, bu olacağından şüpheliyim.

Bu arada, "kullanmanın" kapsamı ve temizleme avantajları onu en sevdiğim C # özelliklerinden biri haline getiriyor. Bu arada, Java, C # ve Python'da ana dillerim olarak çalışıyorum, diğerlerinin birçoğu burada ve oraya fırlatıldı, ve "kullanma" benim en sevdiğim dil özelliklerinden biri. Çünkü pratik, günlük bir çalışma atı. .


5
2017-11-10 20:40



İpucu, kod okunabilirliği için: İç "kullanımı" haricinde kaşlı ayraç içermeyen kullanım bildirimlerini hizalayın ve sıkıştırın. - Bent Tranberg


3. seçeneği beğendim

private object _myDateTimeLock = new object();
private DateTime _myDateTime;

public DateTime MyDateTime{
  get{
    lock(_myDateTimeLock){return _myDateTime;}
  }
  set{
    lock(_myDateTimeLock){_myDateTime = value;}
  }
}

İki seçeneğinizden, ikinci seçenek, neler olduğunu anlamak için en temiz ve kolay.


4
2017-11-10 19:43



Lock deyimi, ReaderWriterLock ile aynı şekilde çalışmıyor. - chakrit
@chakrit: Hayır, ama bilmedikçe aslında kilit çekişmesi daha muhtemeldir. - Michael Burr
Doğru, ama her zaman ilk önce smiple kilidi için gitmelisin. Subby'nin sorusu, bir kilitlemeye izin vermeyecek performans sorunları veya gereksinimleri hakkında hiçbir şey ifade etmemektedir. Bu yüzden denemek ve kaygan olmak için bir sebep yok. Sadece kilitle ve salla. - Will


"Özellikleri demet" ve mülkiyet alıcı ve setter düzeyinde kilitleme yanlış görünüyor. Kilitlemenin çok ince taneli. Çoğu tipik nesne kullanımında, erişmek için bir kilit aldığınızdan emin olmak istersiniz Daha aynı anda bir mülkten daha fazlası. Özel durumunuz farklı olabilir ama ben şüpheliyim.

Neyse, özelliği yerine nesneye eriştiğinizde kilidi almanız, yazmak zorunda kalacağınız kilitleme kodunun miktarını önemli ölçüde azaltacaktır.


4
2017-11-10 21:32



Evet, kesinlikle senin noktasını görüyorum. Benim mülklerimin çoğunun, aslında atomik olması gerektiğinden kilitlenmem gerekmeyen bool'lar, ints. Kilidi almak isteyeceğim bazı tarihler, dize var. çünkü azınlığın kilitlere ihtiyacı olacaktı, ben onu mülke en iyi şekilde yerleştireceğim - Jeremy


KURU diyor ki: ikinci çözüm. İlk çözüm, bir kilit kullanarak mantığını kopyalarken, ikincisi de yoktur.


3
2017-11-10 19:42





Try / Catch blokları genellikle istisna işleme içindir, blokları kullanmak nesnenin atıldığından emin olmak için kullanılır.

Okuma / yazma kilidi için bir deneme / yakalama en kullanışlı olabilir, ancak her ikisini de kullanabilirsiniz:

using (obj)
{
  try { }
  catch { }
}

Böylece, tek kullanımlık arabiriminizi dolaylı olarak arayabilir ve istisna işlemlerini kısa ve öz bir şekilde yapabilirsiniz.


1
2017-11-10 19:43





Bence yöntem 2 daha iyi olurdu.

  • Özelliklerinizdeki daha basit ve daha okunabilir kod.
  • Kilitleme kodunun birkaç kez yeniden yazılması gerekmediğinden daha az hataya eğilimlidir.

0
2017-11-10 19:41