Ten kod jest częścią aplikacji, która odczytuje i zapisuje w bazie danych połączonej z ODBC. Tworzy rekord w bazie danych, a następnie sprawdza, czy rekord został pomyślnie utworzony, a następnie zwraca true
.
Moje rozumienie przepływu kontroli jest następujące:
command.ExecuteNonQuery()
jest udokumentowane, aby InvalidOperationException
zgłosić, gdy „wywołanie metody jest nieprawidłowe dla bieżącego stanu obiektu”. Dlatego, gdyby tak się stało, wykonanie try
bloku zatrzymałoby się, finally
blok zostałby wykonany, a następnie zostałby wykonany return false;
na dole.
Jednak moje IDE twierdzi, że return false;
kod jest nieosiągalny. I wydaje się, że to prawda, mogę go usunąć i kompiluje bez żadnych skarg. Jednak dla mnie wygląda na to, że nie byłoby wartości zwracanej dla ścieżki kodu, w której jest zgłaszany wspomniany wyjątek.
private static bool createRecord(String table,
IDictionary<String,String> data,
System.Data.IDbConnection conn,
OdbcTransaction trans) {
[... some other code ...]
int returnValue = 0;
try {
command.CommandText = sb.ToString();
returnValue = command.ExecuteNonQuery();
return returnValue == 1;
} finally {
command.Dispose();
}
return false;
}
Jaki jest mój błąd zrozumienia?
źródło
Dispose
wyraźnie, ale umieśćusing
:using (var command = ...) {command.CommandText = sb.ToString(); return command.ExecuteNonQuery(); }
finally
Blok oznacza coś innego niż myślisz.Odpowiedzi:
Ostrzeżenie kompilatora (poziom 2) CS0162
To tylko mówi, że Kompilator rozumie wystarczająco poprzez analizę statyczną , że nie można go osiągnąć i całkowicie pomija go w skompilowanym IL (stąd twoje ostrzeżenie)
Uwaga : możesz udowodnić sobie ten fakt, próbując przejść do nieosiągalnego kodu za pomocą debugera lub używając narzędzia IL Explorer
finally
Może uruchomić na wyjątek , (mimo że na bok) nie zmienia faktu (w tym przypadku), to nadal być przechwycony wyjątek . Ergo, ten ostatnireturn
nigdy nie zostanie trafiony.Jeśli chcesz kod do kontynuowania na ostatniej
return
, jedyną opcją jest, aby złapać ten wyjątek ;Jeśli tego nie zrobisz, po prostu zostaw to tak, jak jest i usuń
return
.Przykład
Cytując dokumentację
try-last (odwołanie w C #)
W końcu
Korzystając z czegokolwiek, co obsługuje
IDisposable
interfejs (który jest przeznaczony do zwalniania niezarządzanych zasobów), można opakować to wusing
instrukcję. Kompilator wygenerujetry {} finally {}
wewnętrzne wywołanieDispose()
obiektuźródło
Źle.
finally
nie połyka wyjątku. Szanuje to i wyjątek zostanie zgłoszony normalnie. Wykona kod tylko w końcu przed końcem bloku (z wyjątkiem lub bez).Jeśli chcesz, aby wyjątek został połknięty, powinieneś użyć
catch
bloku bezthrow
w nim.źródło
return false
Kompiluje , ale nigdy nie trafi, ponieważ zamiast tego wyrzuci wyjątek @EhsanSajjadOstrzeżenie jest takie, ponieważ nie użyłeś,
catch
a twoja metoda jest zasadniczo napisana w ten sposób:Ponieważ używasz
finally
wyłącznie do utylizacji, preferowanym rozwiązaniem jest użycieusing
wzoru:To wystarczy, aby zapewnić, jak
Dispose
zostanie nazwane. Jest gwarantowane, że zostanie wywołane albo po pomyślnym wykonaniu bloku kodu, albo po (przed) jegocatch
wyłączeniu w stosie połączeń (połączenia macierzyste są w dół, prawda?).Jeśli nie chodzi o pozbycie się, to
wystarczy, ponieważ nigdy nie będziesz musiał wracać
false
na koniec metody (nie ma potrzeby tego wiersza). Twoja metoda zwraca wynik wykonania polecenia (true
lubfalse
) lub w przeciwnym razie zgłosi wyjątek .Rozważ również zgłoszenie własnych wyjątków przez zawijanie oczekiwanych wyjątków (sprawdź konstruktor InvalidOperationException ):
Zwykle jest to używane do powiedzenia wywołującemu coś bardziej znaczącego (użytecznego) niż mógłby powiedzieć wyjątek zagnieżdżonego połączenia.
W większości przypadków nie obchodzą Cię nieobsługiwane wyjątki. Czasami trzeba upewnić się, że
finally
jest wywoływana, nawet jeśli wyjątek nie jest obsługiwany. W takim przypadku po prostu złap go sam i rzuć ponownie (zobacz odpowiedź ):źródło
Wygląda na to, że szukasz czegoś takiego:
Proszę zauważyć, że
finally
to nie wyklucza żadnego wyjątkuźródło
Nie masz
catch
bloku, więc nadal jest zgłaszany wyjątek, który blokuje powrót.To jest złe, ponieważ ostatni blok zostałby wykonany, a następnie wystąpiłby nieprzechwycony wyjątek.
finally
bloki są używane do czyszczenia i nie przechwytują wyjątku. Wyjątek jest zgłaszany przed powrotem, dlatego zwrot nigdy nie zostanie osiągnięty, ponieważ wcześniej został zgłoszony wyjątek.Twoje IDE jest poprawne, ponieważ nigdy nie zostanie osiągnięte, ponieważ wyjątek zostanie zgłoszony. Tylko
catch
bloki mogą wychwytywać wyjątki.Czytanie z dokumentacji ,
To wyraźnie pokazuje, że final nie jest przeznaczony do wychwytywania wyjątku i byłbyś poprawny, gdyby
catch
przed instrukcją znajdowała się pustafinally
instrukcja.źródło
Gdy wyjątek zostanie zgłoszony, stos się rozwinie (wykonanie wyjdzie z funkcji) bez zwracania wartości, a zamiast tego każdy blok catch w ramkach stosu powyżej funkcji przechwyci wyjątek.
Dlatego
return false
nigdy nie będzie wykonywany.Spróbuj ręcznie zgłosić wyjątek, aby zrozumieć przepływ sterowania:
źródło
W Twoim kodzie:
To jest wada w twojej logice, ponieważ
finally
blok nie przechwyci wyjątku i nigdy nie osiągnie ostatniej instrukcji return.źródło
Ostatnia instrukcja
return false
jest nieosiągalna, ponieważ w bloku try brakujecatch
części, która obsługiwałaby wyjątek, więc wyjątek jest ponownie zgłaszany pofinally
bloku, a wykonanie nigdy nie dochodzi do ostatniej instrukcji.źródło
Masz w kodzie dwie ścieżki powrotu, z których druga jest nieosiągalna z powodu pierwszej. Ostatnia instrukcja w twoim
try
blokureturn returnValue == 1;
zapewnia normalny zwrot, więc nigdy nie możesz dotrzećreturn false;
do końca bloku metody.FWIW, kolejność sprawdzania powiązana z
finally
blokiem jest następująca: najpierw zostanie obliczone wyrażenie dostarczające zwracaną wartość w bloku try, następnie zostanie wykonany ostatni blok, a następnie zostanie zwrócona obliczona wartość wyrażenia (wewnątrz bloku try).Odnośnie przepływu po wyjątku ... bez a
catch
,finally
zostanie wykonany po wyjątku, zanim wyjątek zostanie ponownie wyrzucony z metody; nie ma ścieżki „powrotu”.źródło