Czy w typowym if...else
pakiecie z obsługą wyjątków coś w rodzaju poniższego przykładu jest zalecaną praktyką pozwalającą uniknąć powielania kodu?
try
{
if (GetDataFromServer())
{
return ProcessData();
}
else
{
throw new Exception();
}
catch(Exception ex)
{
return null;
}
zamiast...
try
{
if (GetDataFromServer())
{
return ProcessData();
}
else
{
return null;
}
}
catch(Exception ex)
{
return null;
}
Wiem, że nastąpił niewielki spadek wydajności, ale zastanawiam się, czy uważa się to za dopuszczalną praktykę. Obecnie robię to drugą metodą - szczególnie w przypadkach, w których muszę inaczej obsługiwać określone wyjątki - ale zastanawiałem się, czy pierwsza metoda jest odpowiednia dla prostych przypadków.
c#
exception-handling
gajeNL
źródło
źródło
Odpowiedzi:
Microsoft odradza stosowanie obsługi wyjątków do kontroli przepływu.
Dostępny jest okrągły stół na ten temat.
Biorąc to pod uwagę, C # obsługuje to i przypuszczam, że zależy to od napotkanego warunku, czy wyjątek jest najbardziej odpowiednią odpowiedzią.
źródło
Trafienie w wydajność jest prawdopodobnie znikome, jak wyjaśniono w tej odpowiedzi .
Przejdźmy więc do wniosku, że wydajność nie stanowi problemu. Rzucasz
System.Exception
, aby przenieść egzekucję docatch
klauzuli .BadControlFlowThatShouldBeRewrittenException
Jednak rzucanie byłoby prawdopodobnie przesadą.Rozwalmy to. Mamy:
GetDataFromServer
(nazwy metod powinny być PascalCase w języku C #), które mogą wyrzucić wyjątek lub zwrócić abool
.true
, uruchomProcessData
.null
inaczej.Wygląda na to, że metoda, w której napisany jest ten kod, po prostu robi zbyt wiele rzeczy.
GetDataFromServer
zwracaniebool
wygląda jak błąd projektowy, oczekiwałbym, że ta metoda zwróci dane otrzymywane z serwera , niektóreIEnumerable<SomeType>
zawierające 0 lub więcej elementów - tj. szczęśliwa ścieżka zwraca n elementów, gdzie n> 0 , niezbyt szczęśliwy ścieżka zwraca 0 elementów, a niezadowolona ścieżka wysadza się w powietrze z nieobsługiwanym wyjątkiem, cokolwiek to jest.To bardzo zmienia wygląd metody - znowu trudno jest stwierdzić, czy ma to sens, ponieważ oryginalny post ma tylko jeden punkt wyjścia (a zatem nie skompiluje się, ponieważ nie wszystkie ścieżki kodu zwracają wartość ), więc to tylko dzikie przypuszczenie:
Tutaj możesz zobaczyć
ProcessData
i zobaczyć, że iteruje iteracjęresult
, i zwraca,null
jeśli nie ma żadnego elementu wIEnumerable
.Dlaczego metoda się zwraca
null
? Serwer nie działa? Czy w zapytaniu jest błąd? Ciąg połączenia używa niewłaściwych danych logowania? IlekroćGetDataFromServer
wybuchnie wyjątek, którego się nie spodziewasz, połykasz go, wsuwasz pod dywan i zwracasznull
wartość. W tym przypadku zalecam wychwycenie określonych wyjątków i zapisanie wszystkiego; debugowanie będzie w ten sposób znacznie łatwiejsze.Z ogólną
catch
klauzulą, która nie wychwytuje wyjątku, dość trudno jest zdiagnozować cokolwiek. Zamiast tego zrobiłbym to minimalnie:Teraz możesz przynajmniej złamać i sprawdzić,
e
czy coś pójdzie nie tak.TL; DR : Nie, rzucanie i wyławianie wyjątków dla kontroli przepływu nie jest dobrym pomysłem.
źródło
w twojej pierwszej odpowiedzi jest hit wydajności, który nie musi tam być.
po wyjściu z instrukcji if, aby wejść do instrukcji Catch, gdy nie trzeba zmuszać kodu do zmiany kierunku, że tak powiem.
jeśli chcesz to
return null;
zrobić w instrukcji else, a nie w połowie, który jest złapany po wyrzuceniu z instrukcji else.Prawdopodobnie nie dotyczy twojego prawdziwego kodu, ale ma zastosowanie do kodu ogólnego, który podałeś.
Normy mówią, że nie powinieneś tego robić.
Standardy mówią, że powinieneś to zrobić w ten sposób (ponownie na podstawie kodu ogólnego podanego w OP)
a ponieważ nie masz żadnych wyjątków, które łapiesz, nie powinieneś nawet próbować tutaj łapać.
chcesz zobaczyć wyjątki, gdy wystąpią, aby można było rozwiązać problem, który tworzy wyjątek.
źródło
Dlaczego nie o wiele prostsze:
Jeśli moduł obsługi wyjątków będzie istniał, powinien być w ProcessData ()
źródło
ProcessData()
na najwyższy poziom?ProcessData()
zgłasza wyjątek, teraz nie jest to obsługiwane. Chcę to zrobićreturn null
na tym poziomie, jeśliProcessData()
zgłosi wyjątek, nie zmieniającProcessData()
się.