it-swarm.dev

Bir işlevden erken dönmeli miyim veya bir if ifadesi mi kullanmalıyım?

Sık sık bu tür bir işlevi her iki formatta da yazdım ve bir formatın diğerine göre tercih edilip edilmediğini ve nedenini merak ediyordum.

public void SomeFunction(bool someCondition)
{
    if (someCondition)
    {
        // Do Something
    }
}

veya

public void SomeFunction(bool someCondition)
{
    if (!someCondition)
        return;

    // Do Something
}

Genellikle ilkini kodlarım çünkü kodlama sırasında beynimin çalışması budur, ancak sanırım 2. olanı tercih ediyorum çünkü herhangi bir hata işlemeyi hallediyor ve okumayı daha kolay buluyorum

302
Rachel

İkinci stili tercih ederim. İlk önce geçersiz durumları alın, istisnalardan uygun şekilde çıkın veya uygun şekilde yükseltin, oraya boş bir satır ekleyin, ardından yöntemin "gerçek" gövdesini ekleyin. Okumayı daha kolay buluyorum.

400
Mason Wheeler

Kesinlikle ikincisi. Birincisi şu anda kötü görünmüyor, ancak daha karmaşık bir kod aldığınızda, kimsenin bunu düşüneceğini düşünemiyorum:

public int SomeFunction(bool cond1, string name, int value, AuthInfo perms)
{
    int retval = SUCCESS;
    if (someCondition)
    {
        if (name != null && name != "")
        {
            if (value != 0)
            {
                if (perms.allow(name)
                {
                    // Do Something
                }
                else
                {
                    reval = PERM_DENY;
                }
            }
            else
            {
                retval = BAD_VALUE;
            }
        }
        else
        {
            retval = BAD_NAME;
        }
    }
    else
    {
        retval = BAD_COND;
    }
    return retval;
}

daha okunabilir

public int SomeFunction(bool cond1, string name, int value, AuthInfo perms)
{
    if (!someCondition)
        return BAD_COND;

    if (name == null || name == "")
        return BAD_NAME;

    if (value == 0)
        return BAD_VALUE;

    if (!perms.allow(name))
        return PERM_DENY;

    // Do something
    return SUCCESS;
}

Tek bir çıkış noktasının avantajını hiç anlamadığımı itiraf ediyorum.

169
Jason Viers

Bu bağlıdır - Genel olarak, erken bir işlevden çıkmak için bir grup kodu hareket ettirmek için yolumdan çıkmayacağım - derleyici genellikle benim için bununla ilgilenecektir. Bununla birlikte, üstte ihtiyacım olan ve başka türlü devam edemeyen bazı temel parametreler varsa, erken kopacağım dedi. Benzer şekilde, bir koşul işlevde dev if bloğu oluşturursa, bunun bir sonucu olarak da erkenden kopacaktır.

Bununla birlikte, bir işlev çağrıldığında bazı veriler gerektiriyorsa, genellikle geri dönmenin aksine bir istisna (örneğe bakın) atacağım.

public int myFunction(string parameterOne, string parameterTwo) {
  // Can't work without a value
  if (string.IsNullOrEmpty(parameterOne)) {
    throw new ArgumentNullException("parameterOne");
  } 
  if (string.IsNullOrEmpty(parameterTwo)) {
    throw new ArgumentNullException("parameterTwo");
  }

  // ...      
  // Do some work
  // ...

  return value;
}
32
rjzii

Erken dönüşü tercih ederim.

Bir giriş noktanız ve bir çıkış noktanız varsa, o zaman her zaman kafanızdaki tüm kodu çıkış noktasına kadar takip etmelisiniz (aşağıdaki diğer bir kod parçasının sonuca başka bir şey yapıp yapmadığını asla bilemezsiniz, böylece var olana kadar takip etmek zorunda). Nihai sonucu hangi branşta belirleyecek bir malzeme yok. Bunu takip etmek zor.

Bir giriş ve birden fazla giriş olduğunda, sonucunuz elinize ulaştığında geri dönersiniz ve hiç kimsenin kendisine başka bir şey yapmadığını görmek için bunu izlemekten rahatsız olursunuz (çünkü döndüğünüzden beri başka bir şey olmayacak). Yöntem gövdesinin daha fazla aşamaya bölünmesi gibi, her adımın sonucu döndürme veya bir sonraki adımın şansını denemesine izin verme gibi.

24
user7197

Manuel olarak temizlemeniz gereken C programlamasında tek noktadan dönüş için söylenecek çok şey vardır. Şu anda bir şeyi temizlemeye gerek olmasa bile, birisi işlevinizi düzenleyebilir, bir şey tahsis edebilir ve geri dönmeden önce temizlemesi gerekebilir. Bu olursa, tüm iade beyanlarını inceleyen bir kabus işi olacaktır.

C++ programlamasında yıkıcılarınız ve hatta şimdi kapsam-çıkış korumalarınız var. Tüm bunların, kodun ilk etapta istisna açısından güvenli olmasını sağlamak için burada olması gerekir, bu nedenle kod erken çıkışa karşı iyi korunur ve bu nedenle mantıksal bir dezavantajı yoktur ve tamamen bir stil sorunudur.

Java hakkında yeterince bilgili değilim, "sonunda" blok kodu çağrılacak ve sonlandırıcıların bir şey olmasını sağlamak için ihtiyaç duyabilecek durumda olup olmadığını.

C # Kesinlikle cevap veremem.

D-dili size uygun dahili kapsam-çıkış korumaları sağlar ve bu nedenle erken çıkış için iyi hazırlanmıştır ve bu nedenle stil dışında bir sorun oluşturmamalıdır.

Tabii ki işlevler ilk etapta o kadar uzun olmamalı ve büyük bir anahtar deyiminiz varsa, kodunuz da muhtemelen kötü faktörlüdür.

13
CashCow

Her ikisini de kullanıyorum.

DoSomething 3-5 kod satırı ise, kod sadece ilk biçimlendirme yöntemini kullanarak güzel görünür.

Ama bundan çok daha fazla satırı varsa, ikinci formatı tercih ederim. Açılış ve kapanış parantezleri aynı ekranda olmadığında hoşlanmıyorum.

9
azheglov

Kazanma için erken getiri. Özellikle kontrol etmek için birden fazla koşul varsa, çirkin görünebilirler, ancak büyük if paketleyicilerinden çok daha az çirkin görünebilirler.

9
STW

Tek giriş-tek çıkış için klasik bir neden, aksi takdirde biçimsel anlambilimin aksi halde çirkinleşmesidir (aynı nedenin GOTO'nun zararlı olduğu düşünüldü).

Başka bir deyişle, sadece 1 dönüşünüz varsa, yazılımınızın rutinden ne zaman çıkacağını anlamak daha kolaydır. Bu da istisnalara karşı bir argüman.

Genellikle erken dönüş yaklaşımını en aza indiririm.

8
Paul Nathan

Şahsen ben başlangıçta başarılı/başarısız koşulu kontrolleri yapmayı tercih ederim. Bu, en sık karşılaşılan hataların çoğunu, izlenecek mantığın geri kalanıyla birlikte işlevin üst kısmında gruplandırmamı sağlar.

7
nathan

Değişir.

İşlevin geri kalanını anlamsız kılacak hemen kontrol etmek için bariz bir çıkmaz koşul varsa erken dönüş. *

İşlev daha karmaşıksa ve birden çok çıkış noktasına sahipse Retval + tek dönüşü ayarlayın (okunabilirlik sorunu).

* Bu genellikle bir tasarım problemi olduğunu gösterebilir. Kodunuzun geri kalanını çalıştırmadan önce yöntemlerinizin birçoğunun harici/paramater durumunu kontrol etmesi gerektiğini fark ederseniz, bu muhtemelen arayan tarafından ele alınması gereken bir şeydir. .

6
Bobby Tables

Bir If kullanın

Don Knuth'un GOTO'larla ilgili kitabında onu okudum, her zaman bir if ifadesinde her zaman en olası koşulun ilk gelmesi için bir neden verin. Bunun hala makul bir fikir olduğu varsayımı altında (ve dönemin hızı için saf bir düşünce değil). Kodunuzun başarısız olmamasından daha başarısız olma olasılığı daha yüksek olmadıkça, erken dönüşlerin iyi bir programlama uygulaması olmadığını söyleyebilirim, özellikle hata işleme için kullanılmadığından daha sık oldukları gerçeği göz önünde bulundurulur :-)

Yukarıdaki tavsiyelere uyursanız, bu dönüşü işlevin altına koymanız gerekir ve daha sonra buna bir dönüş bile demezsiniz, sadece hata kodunu ayarlayın ve iki satır döndürün. Böylece 1 giriş 1 çıkış ideal ulaşmak.

Delphi Özel ...

Ben delil olmamasına rağmen, bu Delphi programcılar için iyi bir programlama uygulaması olduğunu düşünüyorum. D2009 öncesi, bir değer döndürmek için atomik bir yolumuz yok, exit; ve result := foo; ya da istisnalar atabiliriz.

Eğer ikame etmek zorunda olsaydın

if (true) {
 return foo;
} 

for

if true then 
begin
  result := foo; 
  exit; 
end;

sadece işlevlerinizin her birinin en üstünde görmeyi bilebilir ve tercih edebilirsiniz

if false then 
begin
  result := bar;

   ... 
end
else
   result := foo;

ve tamamen exit olmaktan kaçının.

3
Peter Turner

Aşağıdaki beyanı kabul ediyorum:

Ben şahsen ben koruma cümleleri hayranıyım (ikinci örnek) çünkü fonksiyonun girintisini azaltır. Bazı insanlar onları sevmez, çünkü bu işlevden birden fazla dönüş noktasıyla sonuçlanır, ancak bence onlarla daha açıktır.

stackoverflow'daki bu sor 'den alınmıştır.

2
Toto

Yazmayı tercih ederim:

if(someCondition)
{
    SomeFunction();
}
1
Josh K

Senin gibi ben genellikle ilkini yazıyorum ama sonuncuyu tercih ediyorum. İç içe geçmiş denetimlerin bir sürü varsa, genellikle ikinci yönteme refactor.

Hata işlemenin çekten nasıl uzaklaştırıldığını sevmiyorum.

if not error A
  if not error B
    if not error C
      // do something
    else handle error C
  else handle error B
else handle error A

Bunu tercih ederim:

if error A
  handle error A; return
if error B
  handle error B; return
if error C
  handle error C; return

// do something
1
jolt

Bu günlerde erken dönüşleri neredeyse sadece aşırı derecede kullanıyorum. Bunu yazarım

self = [super init];

if (self != nil)
{
    // your code here
}

return self;

gibi

self = [super init];
if (!self)
    return;

// your code here

return self;

ama gerçekten önemli değil. İşlevlerinizde birden fazla veya daha fazla iç içe yerleştirme seviyeniz varsa, bunların yakalanması gerekir.

1
Dan Rosenstark

Üstteki koşullara "önkoşullar" denir. if(!precond) return; koyarak, tüm ön koşulları görsel olarak listelersiniz.

Büyük "if-else" bloğunun kullanılması girinti ek yükünü artırabilir (3 seviyeli girintiler hakkındaki alıntıyı unuttum).

0
Ming-Tang