Pytanie dlaczego instrukcja return ma poprzedzać instrukcję throw w bloku catch


Poniższy kod będzie narzekał

try
{
    session.Save(obj);
    return true;
}
catch (Exception e)
{
    throw e;
    return false;  // this will be flagged as unreachable code
}

to nie będzie:

try
{
    session.Save(obj);
    return true;
}
catch (Exception e)
{
    return false;
    throw e;
}

Nie rozumiem ... Myślałem, że mój csc101 powiedział mi, że instrukcje return powinny zawsze być ostatnim stwierdzeniem funkcji i że wychodzi z funkcji i zwraca kontrolę do kodu wywołującego. Dlaczego jest to sprzeczne z logiką mojego profesora i dlaczego tylko jedno z nich generuje ostrzeżenie?


10
2017-09-26 10:21


pochodzenie


"csc101 powiedział mi, że zwrotne instrukcje powinny zawsze być ostatnim stwierdzeniem w funkcji": Wzywam to jako przestarzałą radę Djikstry, która odnosiła się do bardziej przestarzałych języków, które mają różne modele przydzielania / czyszczenia zasobów. - spender
czy to C # czy Java? - Alvin Wong
C # ... jest inny java? - sirbombay
throw wychodzi z funkcji w ten sam sposób return robi. Cokolwiek po tych dwóch wypowiedziach w tym samym bloku nigdy nie zostanie wykonane. W twoim przypadku musisz throw e lub return false. Jeśli chcesz zrobić oba, musisz nieco zmienić swoją funkcję. - Michael Aquilina
heh; btw - myślę, że masz na myśli "defies", a nie "defiles" - Marc Gravell♦


Odpowiedzi:


return opuści metodę; throw będzie również wyjdź z tej metody, zakładając, że nie ma jej w środku try. Może wyjść tylko raz!

Tak więc niezależnie od kolejności - pierwszy z throw / return skutecznie zakończyć metodę.

Jednak bardziej ogólna informacja zwrotna: jeśli celem jest zwrócenie błędu po niepowodzeniu, wystarczy:

try
{
    session.Save(obj);
    return true;
}
catch
{
    return false;
}

Osobiście powiedziałbym, że jest to zły kod - ukrywa on rzeczywisty problem od wywołującego, co bardzo utrudnia debugowanie. Nic nam to nie mówi czemu nie powiodło się. Powiedziałbym, że lepszym rozwiązaniem jest po prostu pozwól bańce wyjątków. W takim przypadku nie ma sensu powracać true, ponieważ nigdy nie wrócimy false - i nie ma sensu chwytanie wyjątku tylko po to, żeby go ponownie rzucić. Tak więc cała metoda staje się:

session.Save(obj);

(nic więcej nie jest wymagane)


Jeśli twoje pytanie brzmi "dlaczego tylko jedno z nich generuje ostrzeżenie": sprawiedliwe pytanie, ale kompilator nie jest wymagany zauważyć zarówno z nich dla ciebie. Być może powinien to zauważyć. ja posądzać że gmcs  by zauważ to i ostrzegaj - kompilator w mono jest o wiele bardziej skłonny wskazać głupotę.


Edytuj: zgodnie z oczekiwaniami, [g] mcs wyjścia:

Program.cs(15,13): warning CS0162: Unreachable code detected
Program.cs(28,13): warning CS0162: Unreachable code detected

dla kodu poniżej - tak więc rzeczywiście zgłasza oba zastosowania jako ostrzeżenia:

class Program
{
    static void Main() { }
    static void DoSomething() { }
    bool ReturnFirst()
    {
        try
        {
            DoSomething();
            return true;
        }
        catch
        {
            return false;
            throw; // line 15
        }
    }
    bool ThrowFirst()
    {
        try
        {
            DoSomething();
            return true;
        }
        catch
        {
            throw;
            return false; // line 28
        }
    }
}

12
2017-09-26 10:36



Odpowiedź jest bardziej szczegółowa i zasługuje na właściwą poprawną odpowiedź w serwisie answer.pl, aby uwzględnić scenariusz, w którym intencją jest poinformowanie rozmówcy o tym, czy nie jest ono poprawne, czy też nie (obiekt) się powiedzie ... i nadal chce propagować wyjątek w górę. - sirbombay
@birbombay, który nie ma sensu: sposób, w jaki wiedzą, czy się udało, czy nie, jest po prostu przez czy pojawił się wyjątek. Nie może obie return false i wyrzucić wyjątek - to po prostu nie ma sensu. - Marc Gravell♦
Spotkałem się dzisiaj z tą głupią kompilacją kompilatora i naprawdę pomyślałem, że kiedyś może to być instrukcja throw, nawet po instrukcji return? Dziękuję za Twoją odpowiedź. - Tarık Özgün Güner
Jak przetestowano możesz użyć instrukcji throw z return jako "Exception ex2; try {...} catch (Exception ex) {ex2 = ex; return;} finally {throw ex2;} - Tarık Özgün Güner
Poprawione rozwiązanie tutaj: "Exception ex2 = null; try {...} catch (Exception ex) {ex2 = ex; return;} finally {if (ex2! = Null) {throw ex2;}}" Przepraszamy za spamowanie. - Tarık Özgün Güner


Mylisz się: obie twoje przykłady podnoszą Martwy kod błąd kompilatora, ponieważ oba throw i return oznacz punkt wyjścia metody, a poza tym punktem nie jest dozwolony żaden inny kod.

Niezależnie od tego, czy kompilator na to pozwala, czy nie, kod poniżej albo throw albo return jest nadal martwy i nigdy nie będzie miał szansy na wykonanie.

(UWAGA: to pytanie zostało początkowo oznaczone jako Java, a moje pierwsze zdanie dotyczy semantyki kompilatora Java)


12
2017-09-26 10:24



+1 dla jedynej poprawnej odpowiedzi. (Inne wkrótce się poprawią) - xyz
@musefan: chodzi mi o to, że samo to pytanie jest błędne, ponieważ oba kody powodują błąd kompilacji. - xyz
Nie w VS2012, the return -> throw nie dawaj ostrzeżenia podczas throw -> return tak. - Alessandro D'Andria
@ AlessandroD'Andria: Potwierdź, że to jest poprawne (C # w VS 2012) - musefan
używam vs2008 i pozwala na drugi blok kodu podczas zaznaczania pierwszego - sirbombay


Ponieważ jakikolwiek kod po instrukcji return w bloku kodu będzie nieosiągalny.


1
2017-09-26 10:24





Ta odpowiedź jest oparta na języku C # i może lub nie może być stosowana w Javie.

W takim przypadku faktycznie nie potrzebujesz return komunikat. throw będzie ostatnim krokiem funkcji.

W tym przykładzie oba return i throw zakończy bieżącą funkcję. Bez względu na to, w którą stronę się je znajduje, najpierw zawsze zapobiegnie osiągnięciu drugiego.

UWAGA: Wyjątek od kiedy throw oświadczenie zakończyłoby funkcję, gdyby miało być opakowane w try blok. W tym przypadku throw funkcja zakończy działanie pozostałych trykod bloku i przejdź do najbardziej odpowiedniego catch blok - lub finally blokować, jeśli a catch nie ma zastosowania.

Twój kod powinien wyglądać tak:

try
{
    session.Save(obj);

    return true;
}
catch(Exception e)
{
    throw e;
}

Jednak nie ma sensu, aby spróbować / złapać, jeśli wszystko, co robisz, to ponowne rzucanie wyjątku.


Aby odpowiedzieć na Twoje jedyne pytanie:

Dlaczego to niweczy logikę mojego profesora?

Cóż albo twój profesor się myli, albo źle je zrozumiałeś


0
2017-09-26 10:24





"Return false;" w bloku catch jest nieosiągalny z powodu "throw e;" tuż przed tym. Kiedy kod wykonuje się w bloku catch, pierwsza linia jest rzutem, co oznacza, że ​​natychmiast rzucasz wyjątek do metody wywołującej, a zatem żaden poniższy kod nie zostanie wykonany.

try
    {
        session.Save(obj);
        return true;
    }
    catch(Exception e)
    {
        throw e; //Throws exception to calling method
        return false;  //this will be flagged as unreachable code

    }

Mam nadzieję, że to pomoże.


0
2017-09-26 10:32