Como usar a palavra-chave throws do estilo Java em C #?

89

Em Java, a throwspalavra - chave permite que um método declare que não tratará uma exceção por conta própria, mas sim a lançará para o método de chamada.

Existe uma palavra-chave / atributo semelhante em C #?

Se não houver equivalente, como você pode obter o mesmo (ou similar) efeito?

Louis Rhys
fonte

Respostas:

75

Em Java, você deve tratar uma exceção ou marcar o método como aquele que pode lançá-lo usando a throwspalavra - chave.

C # não tem esta palavra-chave ou uma equivalente, como em C #, se você não tratar uma exceção, ela irá borbulhar, até ser detectada ou se não for detectada, o programa será encerrado.

Se você quiser lidar com isso, em seguida, lançar novamente, você pode fazer o seguinte:

try
{
  // code that throws an exception
}
catch(ArgumentNullException ex)
{
  // code that handles the exception
  throw;
}
Oded
fonte
1
"vai borbulhar", isso significa que isso é equivalente a todos os métodos que têm uma cláusula throws em Java?
Louis Rhys
1
@Louis RH - mais ou menos. Isso significa que uma exceção, se não tratada, irá subir na cadeia de chamadas através de cada função de chamada até ser tratada.
Oded
1
@Louis RH não completamente, isso significaria que você teria que capturar a Exceção pelo menos em seu Principal para compilar o código. Como o C # não conhece as exceções verificadas, depende de você capturá-las, caso contrário, elas apenas pousarão no tempo de execução e interromperão seu código.
Johannes Wachter
1
@jwatcher: um método principal também pode ter uma cláusula de lançamento.
Louis Rhys
4
@AshishKamble - eh. Questão de opinião. O tratamento de exceções é diferente no .NET. Não presuma que você sabe o que é "melhor".
Oded
105

O op está perguntando sobre o equivalente em C # da throwscláusula Java - não a throwpalavra - chave. Isso é usado em assinaturas de método em Java para indicar que uma exceção verificada pode ser lançada.

Em C #, não há equivalente direto de uma exceção verificada do Java. C # não tem cláusula de assinatura de método equivalente.

// Java - need to have throws clause if IOException not handled
public void readFile() throws java.io.IOException {
  ...not explicitly handling java.io.IOException...
}

traduz para

// C# - no equivalent of throws clause exceptions are unchecked
public void ReadFile() 
{
  ...not explicitly handling System.IO.IOException...
}
serg10
fonte
30

Sim, este é um tópico antigo, mas frequentemente encontro tópicos antigos quando estou pesquisando respostas no Google, então decidi adicionar algo útil que encontrei.

Se você estiver usando o Visual Studio 2012, há uma ferramenta integrada que pode ser usada para permitir um equivalente de "lançamento" de nível de IDE.

Se você usar os Comentários de documentação XML , conforme mencionado acima, poderá usar a tag <exception> para especificar o tipo de exceção lançada pelo método ou classe, bem como informações sobre quando ou por que ela é lançada.

exemplo:

    /// <summary>This method throws an exception.</summary>
    /// <param name="myPath">A path to a directory that will be zipped.</param>
    /// <exception cref="IOException">This exception is thrown if the archive already exists</exception>
    public void FooThrowsAnException (string myPath)
    {
        // This will throw an IO exception
        ZipFile.CreateFromDirectory(myPath);
    }
Mvanella
fonte
4
OP, esta é sua resposta. Estou supondo, mas JAVA throwsprovavelmente não significa nada para o tempo de execução, além de ser informativo para o desenvolvedor. Da mesma forma, o que @mvanella apontou aqui é a maneira do C # de fazer exatamente o mesmo. Presumo que você já saiba que esta "documentação xml" tem um propósito mais significativo. Eu sei que este tópico é antigo.
Hari Lubovac
Na verdade, o Java não cria exceções, a menos que seja explicitamente especificado em uma throwscláusula ou acionado por um throwcomando. Isso significa que se ocorrer uma RunTimeException e não for tratada no mesmo método em que ocorre, a execução será interrompida aí.
Pedro Lima
18

Aqui está uma resposta a uma pergunta semelhante que acabei de encontrar em bytes.com :

A resposta curta é não. Não há exceções verificadas em C #. O designer da linguagem discute esta decisão nesta entrevista:

http://www.artima.com/intv/handcuffs.html

O mais próximo que você pode obter é usar as tags em sua documentação XML e distribuir documentos gerados por NDoc com seu código / assemblies para que outras pessoas possam ver quais exceções você lança (que é exatamente o que o MS faz na documentação do MSDN). Você não pode confiar no compilador para informá-lo sobre as exceções não tratadas, como você pode estar acostumado em java.

Andreas Dolk
fonte
7

Depois de passar pela maioria das respostas aqui, gostaria de acrescentar algumas idéias.

  1. Confiar nos comentários da documentação XML e esperar que outros confiem é uma escolha ruim. A maior parte do código C # que encontrei não documenta métodos completa e consistentemente com Comentários de documentação XML. E há o maior problema de que, sem as exceções verificadas em C #, como você poderia documentar todas as exceções que seu método lança para que o usuário da API saiba como lidar com todas individualmente? Lembre-se de que você só conhece aqueles em que se lança com a palavra-chave throw em sua implementação. APIs que você está usando dentro de sua implementação de método também podem lançar exceções que você não conhece, porque podem não estar documentadas e você não está lidando com elas em sua implementação, então elas explodirão em face do chamador de seu método. Em outras palavras,

  2. Andreas vinculou uma entrevista com Anders Hejlsberg nas respostas aqui sobre por que a equipe de design do C # decidiu contra as exceções verificadas. A resposta final para a pergunta original está oculta nessa entrevista:

Os programadores protegem seu código escrevendo try finally em todo lugar, então eles voltarão corretamente se ocorrer uma exceção, mas eles não estão realmente interessados ​​em lidar com as exceções.

Em outras palavras, ninguém deve estar interessado em que tipo de exceção pode ser esperada para uma API em particular, pois você sempre irá capturar todas elas em todos os lugares. E se você quiser realmente se preocupar com exceções específicas, como tratá-las depende de você e não de alguém definindo uma assinatura de método com algo como a palavra-chave Java throws, forçando o tratamento de uma exceção específica em um usuário API.

-

Pessoalmente, estou dividido aqui. Concordo com Anders que verificar as exceções não resolve o problema sem adicionar problemas novos e diferentes. Assim como com os comentários da documentação XML, raramente vejo código C # com tudo incluído nos blocos try finally. Parece-me que esta é realmente sua única opção e algo que parece uma boa prática.

Tobias
fonte
3

Na verdade, não ter verificado exceções em C # pode ser considerado uma coisa boa ou ruim.

Eu mesmo considero uma boa solução, uma vez que as exceções verificadas fornecem os seguintes problemas:

  1. Exceções técnicas vazando para a camada de negócios / domínio porque você não pode tratá-las adequadamente no nível inferior.
  2. Eles pertencem à assinatura do método, que nem sempre funciona bem com o design da API.

Por causa disso, na maioria dos aplicativos maiores, você verá o seguinte padrão frequentemente quando ocorrerem exceções marcadas:

try {
    // Some Code
} catch(SomeException ex){
    throw new RuntimeException(ex);
}

O que significa essencialmente emular a maneira como C # / .net lida com todas as exceções.

Johannes Wachter
fonte
Não consigo imaginar como as exceções verificadas se misturariam aos lambdas!
Gabe
@Gabe: Tenho certeza de que você poderia criar algum conceito que permita misturá-los, mas, como eu disse, as exceções verificadas em Java também não são boas práticas, especialmente em aplicativos mais complexos. Portanto, é bom que eles não existam em C #.
Johannes Wachter
3

Você está perguntando sobre isso:

Relançando uma exceção

public void Method()
{
  try
  {
      int x = 0;
      int sum = 100/x;
  }
  catch(DivideByZeroException e)
  {
      throw;
  }
}

ou

static void Main() 
    {
        string s = null;

        if (s == null) 
        {
            throw new ArgumentNullException();
        }

        Console.Write("The string s is null"); // not executed
    }
Pranay Rana
fonte
3
1 para usar throw. Ao usá-lo, o rastreamento da pilha não será perdido.
Giuseppe Accaputo
2

Existem algumas semelhanças fugazes entre o .Net CodeContract EnsuresOnThrow<>e o throwsdescritor java , em que ambos podem sinalizar para o chamador como o tipo de exceção que pode ser levantada a partir de uma função ou método, embora também haja diferenças importantes entre os 2:

  • EnsuresOnThrow<>vai além de apenas declarar quais exceções podem ser lançadas, mas também estipula as condições sob as quais elas têm garantia de serem lançadas - isso pode ser um código bastante oneroso no método chamado se a condição de exceção não for fácil de identificar. Java throwsfornece uma indicação de quais exceções podem ser lançadas (isto é, IMO, o foco em .Net está dentro do método que contrai para provar o throw, enquanto em Java o foco muda para o chamador para reconhecer a possibilidade da exceção).
  • .Net CC não faz distinção entre exceções verificadas e não verificadas que o Java possui, embora a seção 2.2.2 do manual CC mencione

"use pós-condições excepcionais apenas para aquelas exceções que um chamador deve esperar como parte da API"

  • Em .Net, o chamador pode determinar se deve ou não fazer algo com a exceção (por exemplo, desativando contratos). Em Java, o chamador deve fazer algo , mesmo se adicionar um throwspara a mesma exceção em sua interface.

Manual de Contratos de Código aqui

StuartLC
fonte
0

Se o propósito do método c # for apenas lançar uma exceção (como o tipo de retorno js diz), eu recomendaria apenas retornar essa exceção. Veja o exemplo abaixo:

    public EntityNotFoundException GetEntityNotFoundException(Type entityType, object id)
    {
        return new EntityNotFoundException($"The object '{entityType.Name}' with given id '{id}' not found.");
    }

    public TEntity GetEntity<TEntity>(string id)
    {
        var entity = session.Get<TEntity>(id);
        if (entity == null)
            throw GetEntityNotFoundException(typeof(TEntity), id);
        return entity;
    }
ADMITEM
fonte
0

Para quem está se perguntando, você não precisa nem definir o que captura para passar para o próximo método. No caso de você querer todo o tratamento de erros em um thread principal, você pode apenas pegar tudo e repassar assim:

try {
    //your code here
}
catch {
    //this will throw any exceptions caught by this try/catch
    throw;
}
Simon Jensen
fonte