Este código é parte de um aplicativo que lê e grava em um banco de dados ODBC conectado. Ele cria um registro no banco de dados e, em seguida, verifica se um registro foi criado com sucesso e retorna true
.
Meu entendimento do fluxo de controle é o seguinte:
command.ExecuteNonQuery()
está documentado para lançar um InvalidOperationException
quando "uma chamada de método é inválida para o estado atual do objeto". Portanto, se isso acontecer, a execução do try
bloco será interrompida, o finally
bloco será executado e, a seguir, será executado return false;
na parte inferior.
No entanto, meu IDE afirma que o return false;
código é inacessível. E parece ser verdade, posso removê-lo e compilá-lo sem reclamações. No entanto, para mim, parece que não haveria valor de retorno para o caminho do código onde a exceção mencionada é lançada.
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;
}
Qual é o meu erro de compreensão aqui?
fonte
Dispose
explicitamente, mas coloqueusing
:using (var command = ...) {command.CommandText = sb.ToString(); return command.ExecuteNonQuery(); }
finally
bloqueio significa outra coisa do que você pensa.Respostas:
Aviso do compilador (nível 2) CS0162
O que significa apenas dizer que o compilador entende o suficiente por meio da análise estática que não pode ser alcançado e o omite completamente do IL compilado (daí o seu aviso)
Nota : Você pode provar esse fato para si mesmo, tentando acessar o código inacessível com o depurador ou usando um IL Explorer
O
finally
pode ser executado em uma exceção , (embora isso à parte) não muda o fato (neste caso) de que ainda será uma exceção não detectada . Portanto, o últimoreturn
nunca será atingido de qualquer maneira.Se você quiser que o código continue até o último
return
, sua única opção é Catch the Exception ;Se não, apenas deixe do jeito que está e remova o
return
.Exemplo
Para citar a documentação
try-finally (referência C #)
Por último
Ao usar qualquer coisa que suporte a
IDisposable
interface (que é projetada para liberar recursos não gerenciados), você pode envolvê-la em umausing
instrução. O compilador irá gerar umtry {} finally {}
e chamar internamenteDispose()
no objetofonte
Errado.
finally
não engole a exceção. Ele o honra e a exceção será lançada normalmente. Ele apenas executará o código no final antes do final do bloco (com ou sem exceção).Se você quiser que a exceção seja engolida, você deve usar um
catch
bloco sem nenhumthrow
.fonte
return false
acertará, pois lançará uma exceção em vez disso @EhsanSajjadO aviso é porque você não usou
catch
e seu método é basicamente escrito assim:Já que você usa
finally
apenas para descartar, a solução preferida é utilizar ousing
padrão:Isso é o suficiente, para garantir o que
Dispose
será chamado. É garantido que será chamado após a execução bem-sucedida do bloco de código ou após (antes) de algum pontocatch
baixo na pilha de chamadas (as chamadas dos pais estão inativas, certo?).Se não fosse sobre o descarte, então
é o suficiente, já que você nunca terá que retornar
false
no final do método (não há necessidade dessa linha). Seu método retorna o resultado da execução do comando (true
oufalse
) ou lançará uma exceção caso contrário .Considere também lançar suas próprias exceções envolvendo as exceções esperadas (verifique o construtor InvalidOperationException ):
Isso normalmente é usado para dizer algo mais significativo (útil) para o chamador do que uma exceção de chamada aninhada diria.
Na maioria das vezes, você realmente não se preocupa com exceções não tratadas. Às vezes, você precisa garantir que
finally
seja chamado mesmo se a exceção não for tratada. Nesse caso, você simplesmente o pega e joga novamente (veja esta resposta ):fonte
Parece que você está procurando por algo assim:
Por favor, note que
finally
isso não engole nenhuma exceçãofonte
Você não tem um
catch
bloco, então a exceção ainda é lançada, o que bloqueia o retorno.Isso está errado, porque o bloco finally seria executado e, então, haveria uma exceção não detectada.
finally
blocos são usados para limpeza e não detectam a exceção. A exceção é lançada antes do retorno, portanto, o retorno nunca será alcançado, porque uma exceção é lançada antes.Seu IDE está correto, dizendo que nunca será alcançado, porque a exceção será lançada. Apenas
catch
blocos são capazes de capturar exceções.Lendo a documentação ,
Isso mostra claramente que o finally não tem a intenção de capturar a exceção e você estaria correto se houvesse uma
catch
instrução vazia antes dafinally
instrução.fonte
Quando a exceção é lançada, a pilha será desfeita (a execução será movida para fora da função) sem retornar um valor, e qualquer bloco catch nos quadros de pilha acima da função capturará a exceção.
Portanto,
return false
nunca será executado.Tente lançar uma exceção manualmente para entender o fluxo de controle:
fonte
No seu código:
Esta é a falha em sua lógica porque o
finally
bloco não pegará a exceção e nunca alcançará a última instrução de retorno.fonte
A última instrução
return false
está inacessível, porque o bloco try está faltando umacatch
parte que trataria a exceção, então a exceção é relançada após ofinally
bloco e a execução nunca atinge a última instrução.fonte
Você tem dois caminhos de retorno em seu código, o segundo dos quais é inacessível por causa do primeiro. A última instrução em seu
try
blocoreturn returnValue == 1;
fornece seu retorno normal, portanto, você nunca pode chegarreturn false;
ao final do bloco de método.FWIW, a ordem de execução relacionada ao
finally
bloco é: a expressão que fornece o valor de retorno no bloco try será avaliada primeiro, depois o bloco finally será executado e, em seguida, o valor da expressão calculada será retornado (dentro do bloco try).Com relação ao fluxo na exceção ... sem um
catch
, ofinally
será executado na exceção antes que a exceção seja então relançada do método; não há caminho de "retorno".fonte