2009-08-16 19 views
73

Wyobraźmy sobie następujący kod:Czy to jest zła praktyka, aby użyć zwrotu w metodzie void?

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

    DoThat(); 
} 

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

Czy można użyć zwrotu wewnątrz metody void? Czy ma jakieś kary za wyniki? Albo lepiej byłoby napisać kod tak:

void DoThis() 
{ 
    if (isValid) 
    { 
     DoThat(); 
    } 
} 
+1

Co na temat: void DoThis() {if (isValid) DoThat(); } – Dscoduc

+25

Wyobraź sobie kod? Czemu? To jest tutaj! :-D – STW

+0

To jest dobre pytanie, zawsze uważam, że dobrą praktyką jest używanie zwrotu; aby opuścić metodę lub funkcję. Zwłaszcza w metodzie wyszukiwania danych LINQ o wielu wynikach IQueryable i wszystkie z nich zależą od siebie nawzajem. Jeśli jeden z nich nie ma wyniku, ostrzeż i wyjdź. – Cheung

Odpowiedz

2

Nie ma kary krytyki drugi kawałek kodu jest bardziej czytelny, a tym samym łatwiejsze do utrzymania.

+0

Russell i nie zgadzam się z twoją opinią, ale nie powinieneś był zostać poddany pod głosowanie. +1, by wyrównać. Btw, uważam, że boolean test i powrót w jednej linii, a następnie pusta linia jest wyraźnym wskazaniem, co się dzieje. na przykład Pierwszy przykład Rodrigo. –

+0

Nie zgadzam się z tym. Zwiększenie zagnieżdżania nie poprawia czytelności. Pierwszy fragment kodu używa instrukcji "guard", która jest doskonale zrozumiałym wzorem. – cdmckay

+0

Ja też się nie zgadzam. Klauzule strażnicze, które wcześnie wychodzą z funkcji, są obecnie uważane za Dobrą Rzecz w pomaganiu czytelnikowi w zrozumieniu implementacji. –

147

Powrót w metodzie void nie jest zła, jest powszechną praktyką dla invert if statements to reduce nesting.

A mniej zagnieżdżania w twoich metodach poprawia czytelność kodu i łatwość konserwacji.

W rzeczywistości, jeśli masz metodę void bez instrukcji return, kompilator zawsze wygeneruje na końcu ret instruction.

+13

Krótkie, słodkie i poprawne! – bdd

2

Jest to całkowicie w porządku i nie ma "kary za wyniki", ale nigdy nie należy pisać instrukcji "if" bez nawiasów.

Zawsze

if(foo){ 
    return; 
} 

To sposób bardziej czytelny; i nigdy nie będziesz przypadkowo zakładać, że niektóre części kodu są w tym oświadczeniu, gdy nie są.

+2

czytelny jest subiektywny. imho, wszystko co dodaje się do kodu, który jest zbędny, czyni go mniej czytelnym ... (muszę przeczytać więcej, a potem zastanawiam się, dlaczego tam jest i tracić czas, starając się upewnić, że czegoś nie brakuje) ... ale to jest moje subiektywna opinia –

+10

Lepszym powodem, aby zawsze włączać aparaty ortodontyczne, jest mniej na temat czytelności i więcej na temat bezpieczeństwa. Bez nawiasów klamrowych wszystkim łatwiej jest później naprawić błąd, który wymaga dodatkowych instrukcji w ramach, jeśli nie zwracać uwagi i dodawać je bez dodawania nawiasów klamrowych. Przez uwzględnienie zawsze aparatów ortodontycznych ryzyko to jest wyeliminowane. –

+2

Silky, proszę nacisnąć enter przed swoim '{. Spowoduje to ustawienie '{' with your'} 'w tej samej kolumnie, co znacznie ułatwia czytelność (znacznie łatwiej znaleźć odpowiednie klamry otwierające/zamykające). – Imagist

17

Zła praktyka ??? Nie ma mowy. W rzeczywistości zawsze lepiej jest obsłużyć sprawdzanie poprawności, zwracając z metody najwcześniej, jeśli sprawdzanie poprawności nie powiedzie się. Inaczej spowodowałoby to powstanie ogromnej liczby zagnieżdżonych ifs. Wcześniejsze kończenie poprawia czytelność kodu.

również sprawdzić odpowiedzi na podobne pytanie: Should I use return/continue statement instead of if-else?

1

W tym przypadku, drugi przykład jest lepszy kod, ale to nie ma nic wspólnego ze powrocie z funkcji void, to po prostu dlatego, że drugi kod jest bardziej bezpośredni. Ale powrót z funkcji pustki jest całkowicie w porządku.

6

To nie jest zła praktyka (z wszystkich powodów już wymienionych). Jednak im więcej zwrotów masz w metodzie, tym większe prawdopodobieństwo, że zostanie podzielona na mniejsze metody logiczne.

-1

Nie zgodzę się z tym wszystkim, z tobą młodymi biczami.

Korzystanie z powrotu w środku metody, nieważne czy nie, jest bardzo złą praktyką, z przyczyn, które zostały wyraźnie sformułowane, prawie czterdzieści lat temu, przez zmarłego Edsgera W. Dijkstę, zaczynając od dobrze znanego " Oświadczenie GOTO uznane za szkodliwe "i kontynuowanie w" Programowaniu strukturalnym "autorstwa Dahl, Dijkstra i Hoare.

Podstawową zasadą jest, że każda struktura kontrolna i każdy moduł powinny mieć dokładnie jedną pozycję i jedno wyjście. Wyraźny powrót w środku modułu łamie tę zasadę i sprawia, że ​​znacznie trudniej jest zrozumieć stan programu, co z kolei znacznie utrudnia określenie, czy program jest poprawny, czy też nie (co jest znacznie silniejszą własnością niż "czy wydaje się działać, czy nie").

"Oświadczenie GOTO uznane za szkodliwe" i "Programowanie strukturalne" rozpoczęły rewolucję "Structured Programming" w latach siedemdziesiątych.Te dwie części to powody, dla których mamy teraz, jeśli nie, a zarazem i inne konstrukty kontroli jawnej dzisiaj i dlaczego instrukcje GOTO w językach wysokiego poziomu znajdują się na liście zagrożonych gatunków. (Moja osobista opinia jest taka, że ​​muszą znajdować się na liście gatunków wymarłych).

Warto zauważyć, że Modulator Przepływu Wiadomości, pierwszy kawałek oprogramowania militarnego, który PRZEDE WSZYSTKIM przeszedł testy akceptacyjne za pierwszym razem, bez żadnych odchyleń , zrzeczenie się lub "tak, ale" słownictwo, zostało napisane w języku, który nie miał nawet instrukcji GOTO.

Warto również wspomnieć, że Nicklaus Wirth zmienił semantykę instrukcji RETURN w Oberon-07, najnowszej wersji języka programowania Oberon, czyniąc ją końcową częścią deklaracji procedury wpisanej (tj. Funkcji) , a nie wykonywalne polecenie w treści funkcji. Jego wyjaśnienie zmiany mówiło, że zrobił to dokładnie dlatego, że poprzednia forma z 1-wyjściowego interfejsu programowania strukturalnego.

+0

W jaki sposób wyjątki pasują tutaj? – nairdaen

+1

@John: Przeszliśmy przez nakaz Dykstry o wielokrotnych zwrotach, mniej więcej w tym samym czasie, w którym przekroczyliśmy Pascal (w każdym razie większość). –

+0

Przypadki, w których wymagane są wielokrotne zwroty są często oznakami, że metoda próbuje zrobić zbyt wiele i powinna zostać zmniejszona. Nie zamierzam iść tak daleko, jak John z tym, a oświadczenie zwrotne jako część sprawdzania parametrów może być rozsądnym wyjątkiem, ale dostaję się tam, skąd pochodzi pomysł. – kyoryu

4

Pierwszy przykład to użycie instrukcji strażnika. Od Wikipedia:

w programowaniu komputerowym, strażnik jest wyrażenie logiczne, że musi ocenić true jeśli wykonanie programu jest nadal w oddziale w pytaniu.

Myślę, że posiadanie grupy strażników na szczycie metody to doskonale zrozumiały sposób programowania. Zasadniczo mówi się "nie wykonuj tej metody, jeśli któraś z nich jest prawdziwa".

Tak w ogóle byłoby to tak:

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

    DoThat(); 
} 

myślę, że jest o wiele bardziej czytelny następnie:

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

Jest to kolejny wielki powód do korzystania strażników (w przeciwieństwie do kodu zagnieżdżonych) : Jeśli inny programista doda kod do funkcji, pracuje w bezpieczniejszym środowisku.

Rozważmy:

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

kontra:

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

    obj.DoSomething(); 
} 

Teraz wyobraźmy sobie inny programista dodaje wiersz: 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(); 
} 

Oczywiście, jest to uproszczony przypadek, ale programator posiada załamanie programu w pierwszym (kod zagnieżdżonych) np. W drugim przykładzie (wczesne wyjście ze strażnikami), gdy przejdziesz przez strażnika, twój kod jest bezpieczny przed niezamierzonym użyciem referencji zerowej.

Oczywiście świetny programista nie popełnia takich błędów (często). Lepiej jest jednak zapobiegać niż leczyć - możemy napisać kod w sposób całkowicie eliminujący potencjalne źródło błędów. Zagnieżdżanie zwiększa złożoność, więc najlepsze praktyki zalecają kod refaktoryzacji, aby zmniejszyć zagnieżdżanie.

+0

Tak, ale z drugiej strony, kilka warstw gniazdowania, wraz z ich warunkami, sprawia, że ​​kod jest jeszcze bardziej podatny na błędy, logika trudniejsza do śledzenia i - co ważniejsze - trudniejsza do debugowania. Płaskie funkcje to mniejsze zło, IMO. – Skrim

+17

Twierdzę na * korzyść * zmniejszonego zagnieżdżania! :-) –

+0

Zgadzam się z tym. Również z punktu oporu refaktora łatwiej i bezpieczniej jest refaktoryzować metodę, jeśli obiekt staje się strukturą lub coś, co można zagwarantować, nie będzie miało wartości zerowej. –

-1

Zgłaszanie wyjątków zamiast zwracania niczego, gdy obiekt ma wartość pustą itp.

Twoja metoda oczekuje, że obiekt nie będzie mieć wartości null, a nie jest tak, więc powinieneś wyrzucić wyjątek i pozwolić, aby to zadzwonił.

Ale wczesny powrót nie jest złą praktyką.

Powiązane problemy