Bir void yöntemi içinde return kullanmak kötü bir uygulama mıdır?


92

Aşağıdaki kodu hayal edin:

void DoThis()
{
    if (!isValid) return;

    DoThat();
}

void DoThat() {
    Console.WriteLine("DoThat()");
}

Bir void yöntemi içinde dönüş kullanmak uygun mudur? Performans cezası var mı? Veya şöyle bir kod yazmak daha iyi olur:

void DoThis()
{
    if (isValid)
    {
        DoThat();
    }
}
c#  return  void 

1
Ne hakkında: void DoThis () {if (isValid) DoThat (); }
Dscoduc

30
kodu hayal et? Neden? İşte orada! :-D
STW

Bu iyi bir soru, her zaman geri dönüşü kullanmanın iyi bir uygulama olduğunu düşünüyorum; yöntem veya işlevden çıkmak için. Özellikle birden fazla IQueryable <T> sonucuna sahip bir LINQ veri madenciliği yönteminde ve hepsi birbirine bağlıdır. Birinin sonucu yoksa, uyarın ve çıkın.
Cheung

Yanıtlar:



33

Korumaları kullanmanın başka bir harika nedeni daha vardır (iç içe geçmiş kodun aksine): Başka bir programcı işlevinize kod eklerse, daha güvenli bir ortamda çalışırlar.

Düşünmek:

void MyFunc(object obj)
{
    if (obj != null)
    {
        obj.DoSomething();
    }
}

karşı:

void MyFunc(object obj)
{
    if (obj == null)
        return;

    obj.DoSomething();
}

Şimdi, başka bir programcının şu satırı eklediğini hayal edin: obj.DoSomethingElse ();

void MyFunc(object obj)
{
    if (obj != null)
    {
        obj.DoSomething();
    }

    obj.DoSomethingElse();
}

void MyFunc(object obj)
{
    if (obj == null)
        return;

    obj.DoSomething();
    obj.DoSomethingElse();
}

Açıkçası bu basit bir durumdur, ancak programcı ilk (iç içe kod) durumda programa bir çökme eklemiştir. İkinci örnekte (korumalarla erken çıkış), korumayı geçtiğinizde, kodunuz bir boş referansın kasıtsız kullanımından korunur.

Elbette, harika bir programcı böyle hatalar yapmaz (sıklıkla). Ancak önleme, tedaviden daha iyidir - kodu, bu potansiyel hata kaynağını tamamen ortadan kaldıracak şekilde yazabiliriz. Yerleştirme karmaşıklığı artırır, bu nedenle en iyi uygulamalar, iç içe geçmeyi azaltmak için kodun yeniden düzenlenmesini önerir.


Evet, ancak öte yandan, koşullarıyla birlikte birkaç iç içe yerleştirme katmanı, kodu hatalara daha yatkın hale getirir, mantığı izlemeyi ve - daha da önemlisi - hata ayıklamayı zorlaştırır. Düz işlevler daha az kötüdür, IMO.
Skrim

18
Azaltılmış yuvalama lehine tartışıyorum ! :-)
Jason Williams

Buna katılıyorum. Ayrıca, bir refactor açısından, obj bir yapı haline gelirse veya garanti edebileceğiniz bir şey boş olmayacaksa, yöntemi yeniden düzenlemek daha kolay ve daha güvenlidir.
Phil Cooper

18

Kötü uygulama ??? Olmaz. Aslında, doğrulamaların başarısız olması durumunda en erken yöntemden dönerek doğrulamaları ele almak her zaman daha iyidir. Aksi takdirde, büyük miktarda iç içe geçmiş ifs & els ile sonuçlanır. Erken sonlandırma, kod okunabilirliğini artırır.

Ayrıca benzer bir sorudaki yanıtları kontrol edin: if-else yerine return / continue ifadesini kullanmalı mıyım?


8

Kötü bir uygulama değil (zaten belirtilen tüm nedenlerden dolayı). Bununla birlikte, bir yöntemde ne kadar çok getiri elde ederseniz, daha küçük mantıksal yöntemlere bölünmesi daha olasıdır.


8

İlk örnek bir koruma ifadesi kullanmaktır. Gönderen Vikipedi :

Bilgisayar programlamasında, bir koruma, program yürütmesinin söz konusu dalda devam etmesi için doğru olarak değerlendirilmesi gereken bir mantıksal ifadedir.

Bir yöntemin tepesinde bir grup korumaya sahip olmanın, programlamanın tamamen anlaşılabilir bir yolu olduğunu düşünüyorum. Temelde "bunlardan herhangi biri doğruysa bu yöntemi çalıştırmayın" diyor.

Yani genel olarak şuna benzer:

void DoThis()
{
  if (guard1) return;
  if (guard2) return;
  ...
  if (guardN) return;

  DoThat();
}

Bence bu çok daha okunaklı:

void DoThis()
{
  if (guard1 && guard2 && guard3)
  {
    DoThat();
  }
}

3

Performans kesintisi yoktur, ancak ikinci kod parçası daha okunabilir ve dolayısıyla bakımı daha kolaydır.


Russell senin fikrine katılmıyorum ama buna karşı oy kullanmamalıydın. Bunu eşitlemek için +1. Btw, bir boole testi ve tek bir satırda geri dönüşün ardından boş bir satırın neler olup bittiğinin açık bir göstergesi olduğuna inanıyorum. örneğin, Rodrigo'nun ilk örneği.
Paul Sasik

Ben buna katılmıyorum. İç içe yerleştirmenin artırılması, okunabilirliği iyileştirmez. İlk kod parçası, tamamen anlaşılabilir bir kalıp olan bir "koruma" ifadesi kullanıyor.
cdmckay

Ben de katılmıyorum. Bir işlevden erkenden kurtaran koruma hükümleri, günümüzde okuyucunun uygulamayı anlamasına yardımcı olmak için genellikle İyi Şey olarak kabul edilir.
Pete Hodgson

2

Bu durumda, ikinci örneğiniz daha iyi koddur, ancak bunun bir void işlevinden geri dönmeyle ilgisi yoktur, bunun nedeni ikinci kodun daha doğrudan olmasıdır. Ancak bir boşluk işlevinden dönmek tamamen iyidir.


0

Tamamen sorun değil ve 'performans cezası' yok, ancak parantez olmadan asla bir 'eğer' ifadesi yazmayın.

Her zaman

if( foo ){
    return;
}

Çok daha okunaklı; ve asla yanlışlıkla kodun bazı kısımlarının o ifadenin içinde olduğunu varsaymazsınız.


2
okunabilir özneldir. imho, gereksiz olan koda eklenen herhangi bir şey onu daha az okunabilir kılar ... (Daha fazla okumam gerekiyor ve sonra neden orada olduğunu merak ediyorum ve bir şeyi kaçırmadığımdan emin olmak için zaman harcıyorum) ... ama bu benim öznel görüş
Charles Bretana

10
Diş tellerini her zaman dahil etmenin daha iyi nedeni, okunabilirlikle ilgili daha az ve güvenlik ile ilgilidir. Küme parantezleri olmadan, if'nin bir parçası olarak ek ifadeler gerektiren bir hatayı düzeltmek, yeterince dikkat etmemek ve parantez eklemeden bunları eklemek daha sonra birileri için çok kolaydır. Her zaman diş telleri dahil edilerek bu risk ortadan kalkar.
Scott Dorman

2
İpeksi, lütfen önce enter tuşuna basın {. Bu , aynı sütunda {sizinle }aynı hizaya gelir ve okunabilirliğe büyük ölçüde yardımcı olur (karşılık gelen açık / kapalı parantezleri bulmak çok daha kolay).
imagist

1
@Imagist Bunu kişisel tercihe bırakacağım; ve benim tercih ettiğim şekilde yapıldı :)
Noon Silk

1
Her kapatma küme ayracı, aynı girinti düzeyine yerleştirilmiş bir açık küme ayracı ile eşleştirilirse, hangi ifdeyimlerin yakın parantez gerektirdiğini görsel olarak ayırt etmek kolay olacaktır ve bu nedenle ififadelerin tek bir ifadeyi kontrol etmesi güvenli olacaktır. Açık küme ayracı ile çizgiye geri itmek, ifher çoklu deyimde bir satırlık dikey boşluk kaydeder if, ancak aksi takdirde gereksiz olan bir dar ayraç satırı kullanılmasını gerektirir.
supercat

0

Bu konuda siz genç kancıkçılara katılmayacağım.

Geri dönüşü bir yöntemin ortasında kullanmak, geçersiz veya başka türlü, neredeyse kırk yıl önce, son derece açık bir şekilde ifade edilen nedenlerden dolayı, çok kötü bir uygulamadır, merhum Edsger W. "ve devam ediyor" Structured Programming ", Dahl, Dijkstra ve Hoare tarafından.

Temel kural, her kontrol yapısının ve her modülün tam olarak bir giriş ve bir çıkışa sahip olmasıdır. Modülün ortasındaki açık bir geri dönüş, bu kuralı bozar ve programın durumu hakkında akıl yürütmeyi çok daha zorlaştırır, bu da programın doğru olup olmadığını söylemeyi çok daha zor hale getirir (bu çok daha güçlü bir özelliktir) "işe yarıyor gibi görünüp görünmemesinden").

"GOTO İfadesi Zararlı Olarak Kabul Edildi" ve "Yapılandırılmış Programlama" 1970'lerin "Yapılandırılmış Programlama" devrimini başlattı. Bu iki parça, if-then-else, while-do ve günümüzdeki diğer açık kontrol yapılarına sahip olmamızın ve neden yüksek seviyeli dillerdeki GOTO ifadelerinin Tehlike Altındaki Türler listesinde yer almasının nedenleridir. (Benim kişisel görüşüm, Soyu Tükenmiş Türler listesinde olmaları gerektiği yönünde.)

Şunu da belirtmek gerekir ki, ilk denemede HİÇ sapma, feragat veya "evet, ama" laf kalabalığı olmaksızın kabul testini geçen ilk askeri yazılım parçası olan Mesaj Akış Modülatörünün bile olmayan bir dilde yazıldığını belirtmek gerekir. GOTO beyanı.

Ayrıca Nicklaus Wirth'in Oberon programlama dilinin en son sürümü olan Oberon-07'deki RETURN ifadesinin anlamını değiştirdiğini ve onu bir daktilo edilmiş prosedürün (yani işlev) bildiriminin son parçası haline getirdiğini belirtmek gerekir. işlevin gövdesinde çalıştırılabilir ifade. Değişikliğe ilişkin açıklaması, bunu tam olarak, önceki formun Yapılandırılmış Programlamanın tek çıkış ilkesinin ihlali OLDUĞU için yaptığını söyledi .


2
@John: Pascal'ı aştığımız anda (çoğumuz, neyse) birden fazla geri dönüş hakkındaki Dykstra talimatını aştık.
John Saunders

Birden fazla iadenin gerekli olduğu durumlar genellikle bir yöntemin çok fazla şey yapmaya çalıştığının ve ayrıştırılması gerektiğinin işaretleridir. Bununla John'a kadar gitmeyeceğim ve parametre doğrulamanın bir parçası olarak bir dönüş ifadesi makul bir istisna olabilir, ancak fikrin nereden geldiğini anlıyorum.
kyoryu

@nairdaen: Bu çeyrekte istisnalar konusunda hala tartışmalar var. Benim kılavuzum şudur: Eğer geliştirilmekte olan sistem, orijinal istisnai duruma neden olan sorunu düzeltmek ZORUNDA ve bu kodu yazmak zorunda kalacak adamı kızdırmaktan çekinmem, bir istisna atacağım. Sonra bir toplantıda bağırdım, çünkü adam istisnayı yakalama zahmetine girmedi ve uygulama test sırasında çöktü ve NEDEN sorunu düzeltmesi gerektiğini açıkladım ve işler tekrar düzeldi.
John R. Strohm

Güvenlik ifadeleri ve gotos arasında büyük bir fark var. Gotos'un kötü yanı, herhangi bir yere atlayabilmeleridir, bu yüzden çözülmesi ve hatırlanması çok kafa karıştırıcı olabilir. Koruma ifadeleri tam tersidir - bir yönteme geçitli bir giriş sağlarlar, ardından "güvenli" bir ortamda çalıştığınızı bilirsiniz ve kodun geri kalanını yazarken göz önünde bulundurmanız gereken şeylerin sayısını azaltır (örn. "Bu işaretçinin hiçbir zaman boş olmayacağını biliyorum, bu yüzden bu durumu kod boyunca ele almam gerekmiyor").
Jason Williams

@ Jason: Asıl soru özellikle koruma ifadeleriyle ilgili değil, bir yöntemin ortasındaki rastgele dönüş ifadeleriyle ilgiliydi. Verilen örnek bir koruma olarak görünmektedir. Temel sorun, dönüş sitesinde, yöntemin ne yaptığı ya da yapmadığı hakkında akıl yürütebilmek istemenizdir ve rastgele dönüşler bunu daha da zorlaştırır, çünkü TAM Rastgele GOTO'ların işi zorlaştırdığı nedenlerle aynıdır. Bakınız: Dijkstra, "GOTO Beyanı Zararlı Olarak Kabul Edilir". Sözdizimi tarafında, cdmckay, başka bir yanıtta, korumalar için tercih ettiği sözdizimini verdi; Hangi formun daha okunabilir olduğuna dair fikrine katılmıyorum.
John R. Strohm

0

Koruyucuları kullanırken okuyucuların kafasını karıştırmamak için belirli kurallara uyduğunuzdan emin olun.

  • işlev bir şey yapar
  • korumalar yalnızca işlevdeki ilk mantık olarak tanıtıldı
  • içe olmayan kısım, fonksiyonun temel amacını içerir

Misal

// guards point you to the core intent
void Remove(RayCastResult rayHit){

  if(rayHit== RayCastResult.Empty)
    return
    ;
  rayHit.Collider.Parent.Remove();
}

// no guards needed: function split into multiple cases
int WonOrLostMoney(int flaw)=>
  flaw==0 ? 100 :
  flaw<10 ? 30 :
  flaw<20 ? 0 :
  -20
;

-3

Nesne boş vb. Olduğunda hiçbir şey döndürmek yerine istisna atın.

Yönteminiz nesnenin boş olmamasını bekler ve durum böyle değildir, bu nedenle istisna atmalı ve arayanın bunu işlemesine izin vermelisiniz.

Ancak erken dönüş, aksi takdirde kötü bir uygulama değildir.


1
Cevap soruyu cevaplamıyor. Soru geçersiz bir yöntemdir, bu nedenle geri dönen hiçbir şey yoktur. Ayrıca, yöntemlerin parametreleri yoktur. Dönüş türü bir nesneyse, ancak bu soru için geçerli değilse boş döndürmeme noktasını anlıyorum.
Luke Hammer
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.