Geri dönüşü {} ifadesini kullanarak çağırmak iyi bir yaklaşım mı?


93

Sadece bilmek istiyorum, returnbir usingbloğun içinden arama güvenli / iyi bir yaklaşım mı

Örn.

using(var scope = new TransactionScope())
{
  // my core logic
  return true; // if condition met else
  return false;
  scope.Complete();
}

En sondaki küme ayracının dispose()iptal edileceğini biliyoruz . Fakat yukarıdaki durumda ne olacak, çünkü returnkontrolü verilen kapsamın (AFAIK) dışına atıyor ...

  1. Aranacak mı scope.Complete()?
  2. Ve böylece kapsamın dispose()yöntemi için.

1
Bir kez using{}kapsamı bitti, ilgili nesneler, bertaraf olsun returnwill "mola" kapsam - nesneleri beklendiği gibi tanzim alacak böylece
Shai

4
Senin unutmayın scope.Complete()Yani bunu siz işlem olacak hep geri alma, çağrı sağladığınız örnek ile vurmak asla.
Andy

Ne olursa olsun olsun using'ler dispose()döndüğünüzde denir, bu içeren fonksiyon usingbloğu döndü ve kendisine ait her şeyi yetim edilecektir. Dolayısıyla, scope"tarafından using" elden çıkarılmamış olsa bile (diğerlerinin açıkladığı gibi olacaktır), işlev sona erdiği için yine de elden çıkarılacaktır. C # gotoifadesi olsaydı - gülmeyi bitirdin mi? iyi- o zaman dönüş yerine gotokapanış ayracından sonra geri dönmeden yapabilirsiniz. Mantıksal olarak, scopeyine de atılır, ancak gotoC # koydunuz , bu aşamada mantığı kimin umursadığı.
Superbest


Yanıtlar:


146

Kullanım bloğu sadece bir blok olduğu returniçin usingbloğunuzun içinde aramak tamamen güvenlidir try/finally.

Yukarıdaki örneğinizde iade sonrası true, kapsam elden çıkarılacak ve değer iade edilecektir. return falseVe scope.Complete()olacak değil denilen olsun. DisposeAncak, nihayet bloğunun içinde yer aldığından bağımsız olarak çağrılacaktır.

Kodunuz esasen bununla aynıdır (eğer bu anlaşılmasını kolaylaştırırsa):

var scope = new TransactionScope())
try
{
  // my core logic
  return true; // if condition met else
  return false;
  scope.Complete();
}
finally
{
  if( scope != null) 
    ((IDisposable)scope).Dispose();
}

İşlemi gerçekleştirmenin bir yolu olmadığından işleminizin asla taahhüt edilmeyeceğini lütfen unutmayın scope.Complete().


13
Sen o temizlemek yapmalıdır Dispose olacak denilen olsun. OP ne olduğunu bilmiyorsa using, büyük ihtimalle ne olacağını bilmiyordur finally.
Konrad Rudolph

Geri dönüşlü bir kullanım bloğu bırakmakta sorun yoktur, ancak TransactionScope durumunda, using ifadesinin kendisinde sorun yaşayabilirsiniz: blogs.msdn.com/b/florinlazar/archive/2008/05/05/8459994.aspx
thewhiteambit

Deneyimlerime göre, bu SQL Server CLR Assemblies ile çalışmıyor. Bir MemoryStream Nesnesine başvuran SqlXml alanı içeren bir UDF için sonuçları döndürmem gerektiğinde. "Kullanılmış bir nesneye erişilemiyor " ve " Akış kapatıldığında Okumayı çağırmak için geçersiz girişim. " Mesajı alıyorum, bu yüzden bu senaryoda sızdıran kod yazmaya ve using-ifadesini bırakmaya ZORUNLUyum. :( Tek umudum, SQL
CLR'nin

1
@MikeTeeVee - Temizleyici çözeltiler, (a) do arama yapan bir kişi ya da vardır using, örneğin using (var callersVar = MyFunc(..)) .., yerine akışı verildi ve yoluyla kapatılması için sorumlu olan bir arayan ortalama - kullanarak iç "MyFunc" sahip usingya da açık bir şekilde, ya da (b) MyFunc'ın , güvenli bir şekilde geri aktarılabilecek diğer nesnelere ihtiyaç duyulan her türlü bilgiyi çıkarmasını sağlayın - daha sonra temeldeki veri nesneleri veya akış sizin tarafınızdan atılabilir using. Sızdıran kod yazmak zorunda kalmamalısınız.
ToolmakerSteve

7

Sorun değil - finallycümlecikler ( usingcümlenin kapanış küme parantezinin başlık altında yaptığı şeydir ), kapsam bırakıldığında, nasıl olursa olsun her zaman yürütülür.

Bununla birlikte, bu yalnızca nihayet bloğunda (kullanılırken açıkça ayarlanamaz using) ifadeler için geçerlidir . Bu nedenle, örneğinizde scope.Complete()asla çağrılmaz (derleyicinin sizi erişilemez kod hakkında uyarmasını bekliyorum).


2

Genel olarak iyi bir yaklaşımdır. Ancak sizin durumunuzda, aramadan önce dönerseniz scope.Complete(), TransactionScope'u çöpe atar. Tasarımınıza bağlıdır.

Dolayısıyla, bu örnekte Complete () çağrılmaz ve kapsam, IDisposable arabirimi miras aldığını varsayarak elden çıkarılır.


IDisposable veya wont compile kullanmalıdır.
Chriseyre2000

2

kapsam.Complet kesinlikle önceden çağrılmalıdır return. Derleyici bir uyarı gösterecek ve bu kod asla çağrılmayacaktır.

returnKendisine gelince - evet, onu usingifadenin içinde aramak güvenlidir . Kullanmak, sahnenin arkasındaki blok denemeye çevrilir ve son olarak blok kesinlikle yürütülür.


1

Sağladığınız örnekte bir sorun var; scope.Complete()asla aranmaz. İkinci olarak, returnifadelerin içinde usingifadelerin kullanılması iyi bir uygulama değildir . Aşağıdakilere bakın:

using(var scope = new TransactionScope())
{
    //have some logic here
    return scope;      
}

Bu basit örnekte nokta şudur; scopeifade kullanımı bittiğinde değeri boş olacaktır.

Bu nedenle, ifadeleri kullanarak içeri dönmemek daha iyidir.


1
Sırf 'dönüş kapsamı' anlamsız olduğu için, return ifadesinin yanlış olduğu anlamına gelmez.
Preet Sangha

en iyi uygulamaları kullanmamak, yanlış bir şey yaptığınız anlamına gelmez. Öngörülemeyen sonuçlara yol açabileceğinden kaçınmanın en iyisi olduğu anlamına gelir.
daryal

1
Değeri scopeboş olmayacak - yani olmuş tek şey Dispose()o örneğinde çağrılan olacaktır ve bu nedenle örnek olmalıdır artık kullanılamaz (ama boş değil ve denemek ve kullanmak engelleyen bir şey yok atılan nesne, bu gerçekten tek kullanımlık bir nesnenin uygunsuz bir kullanımı olmasına rağmen).
Lucero

Lucero oldukça haklı. Tek kullanımlık nesneler atıldıktan sonra boş değildir. IsDisposed özelliği doğrudur, ancak null değerine göre kontrol ederseniz yanlış alırsınız ve bu nesneye return scopebir başvuru döndürürsünüz . Bu şekilde, iade sırasında bu referansı atarsanız, GC'nin atılan nesneyi temizlemesini engellersiniz.
ThunderGr

1

Çağrılacağından emin olmak için scope.Complete()sarın try/finally. disposeEğer ile sarın çünkü denir usingbir alternatif olduğunu try/finallybloğu.

using(var scope = new TransactionScope())
{
  try
  {
  // my core logic
  return true; // if condition met else
  return false;
  }
  finally
  {
   scope.Complete();
  }
}

Sanırım şunu söylemek istiyorsun: Kazandıysan - İstersen, olmaz ... Koduna göre :)

0

Bu örnekte, kapsam.Complete () hiçbir zaman çalıştırılmayacaktır. Ancak, return komutu yığına atanan her şeyi temizleyecektir. GC, referansta bulunulmayan her şeyi halledecektir. Dolayısıyla, GC tarafından alınamayan bir nesne olmadıkça sorun yoktur.

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.