Ao escrever algum código de tratamento de exceção particularmente complexo, alguém perguntou, você não precisa ter certeza de que seu objeto de exceção não é nulo? E eu disse claro que não, mas resolvi tentar. Aparentemente, você pode lançar null, mas ainda é uma exceção em algum lugar.
Por que isso é permitido?
throw null;
Neste trecho, felizmente 'ex' não é nulo, mas poderia ser?
try
{
throw null;
}
catch (Exception ex)
{
//can ex ever be null?
//thankfully, it isn't null, but is
//ex is System.NullReferenceException
}
c#
exception-handling
gracejo
fonte
fonte
throw
uma declaração cujo objetivo é lançar uma exceção em primeiro lugar, um aviso não agrega muito valor.Respostas:
Porque a especificação da linguagem espera uma expressão do tipo
System.Exception
lá (portanto,null
é válida nesse contexto) e não restringe essa expressão a ser não nula. Em geral, não há como detectar se o valor dessa expressão énull
ou não. Teria de resolver o problema da parada. O tempo de execução terá que lidar com onull
caso de qualquer maneira. Vejo:Exception ex = null; if (conditionThatDependsOnSomeInput) ex = new Exception(); throw ex;
Eles poderiam, é claro, fazer o caso específico de jogar o
null
literal inválido, mas isso não ajudaria muito, então por que desperdiçar espaço de especificação e reduzir a consistência para obter poucos benefícios?Isenção de responsabilidade (antes de eu levar um tapa de Eric Lippert): Esta é minha própria especulação sobre o raciocínio por trás dessa decisão de design. Claro, eu não estive na reunião de design;)
A resposta à sua segunda pergunta, se uma variável de expressão capturada dentro de uma cláusula catch pode ser nula: Embora a especificação C # não diga se outras linguagens podem causar
null
a propagação de uma exceção, ela define a maneira como as exceções são propagadas:Pois
null
, a afirmação em negrito é falsa. Portanto, embora seja puramente baseado no que a especificação do C # diz, não podemos dizer que o tempo de execução subjacente nunca lançará nulo, podemos ter certeza de que, mesmo se for esse o caso, ele será tratado apenas pelacatch {}
cláusula genérica .Para implementações C # na CLI, podemos consultar a especificação ECMA 335. Esse documento define todas as exceções que a CLI lança internamente (nenhuma das quais são
null
) e menciona que os objetos de exceção definidos pelo usuário são lançados pelathrow
instrução. A descrição dessa instrução é virtualmente idêntica àthrow
instrução C # (exceto que não restringe o tipo do objeto aSystem.Exception
):Acredito que isso seja suficiente para concluir que as exceções detectadas nunca são
null
.fonte
throw null;
.catch { }
cláusula genérica .throw
cujo argumento possa ser um valor nulo, isso não implicaria quethrow null
isso teria que ser legal. Um compilador pode insistir que umthrow
argumento tenha um tipo de classe discernível. Uma expressão like(System.InvalidOperationException)null
deve ser válida em tempo de compilação (executá-la deve causar aNullReferenceException
), mas isso não significa que um não tipadonull
deve ser aceitável.A tentativa de lançar um
null
objeto resulta em uma exceção de referência nula (completamente não relacionada).Perguntar por que você tem permissão para jogar
null
é como perguntar por que você tem permissão para fazer isso:object o = null; o.ToString();
fonte
Retirado daqui :
fonte
Embora não seja possível lançar null em C # porque o lançamento irá detectar isso e transformá-lo em um NullReferenceException, É possível receber null ... Acontece que estou recebendo isso agora, o que causa minha captura (que não era esperando que 'ex' seja nulo) para experimentar uma exceção de referência nula que, em seguida, resulta na morte do meu aplicativo (já que essa foi a última captura).
Portanto, embora não possamos lançar null a partir do C #, o submundo pode lançar null, então é melhor que sua captura mais externa (Exceção) esteja preparado para recebê-la. Apenas para sua informação.
fonte
Eu acho que talvez você não possa - quando você tenta lançar null, ele não consegue, então ele faz o que deveria em um caso de erro, que é lançar uma exceção de referência nula. Portanto, você não está realmente lançando o nulo, você está falhando em lançar o nulo, o que resulta em um lançamento.
fonte
Tentando responder "..a gratidão 'ex' não é nulo, mas poderia ser?":
Uma vez que, sem dúvida, não podemos lançar exceções nulas, uma cláusula catch também nunca terá que capturar uma exceção nula. Portanto, ex nunca poderia ser nulo.
Vejo agora que essa pergunta de fato já foi feita .
fonte
throw null
. Mas isso não lançará uma exceção nula . Em vez disso, comothrow null
tenta invocar métodos em uma referência nula, isso subsequentemente força o tempo de execução a lançar uma instância não nula deNullReferenceException
.Lembre-se de que uma exceção inclui detalhes sobre onde a exceção é lançada. Visto que o construtor não tem ideia de onde deve ser lançado, então só faz sentido que o método de lançamento injete esses detalhes no objeto no ponto em que o lançamento está. Em outras palavras, o CLR está tentando injetar dados em nulos, o que dispara uma NullReferenceException.
Não tenho certeza se isso é exatamente o que está acontecendo, mas explica o fenômeno.
Supondo que isso seja verdade (e não consigo imaginar uma maneira melhor de fazer com que ex seja nulo do que lançar nulo;), isso significaria que ex não pode ser nulo.
fonte
No antigo c #:
Considere esta sintaxe:
public void Add<T> ( T item ) => throw (hashSet.Add ( item ) ? null : new Exception ( "The item already exists" ));
Acho que é bem mais curto do que isso:
public void Add<T> ( T item ) { if (!hashSet.Add ( item )) throw new Exception ( "The item already exists" ); }
fonte