Come utilizzare la parola chiave lanci in stile Java in C #?


89

In Java, la throwsparola chiave consente a un metodo di dichiarare che non gestirà un'eccezione da solo, ma piuttosto la lancia al metodo chiamante.

Esiste una parola chiave / attributo simile in C #?

Se non esiste un equivalente, come puoi ottenere lo stesso (o un effetto simile)?

Risposte:


75

In Java, è necessario gestire un'eccezione o contrassegnare il metodo come uno che potrebbe generarlo utilizzando la throwsparola chiave.

C # non ha questa parola chiave o una equivalente, come in C #, se non gestisci un'eccezione, verrà visualizzata una bolla, finché non viene catturata o se non viene interrotta terminerà il programma.

Se vuoi gestirlo, rilancialo puoi fare quanto segue:

try
{
  // code that throws an exception
}
catch(ArgumentNullException ex)
{
  // code that handles the exception
  throw;
}

1
"si gonfierà", significa che questo è equivalente a tutti i metodi che hanno una clausola throws in Java?
Louis Rhys

1
@Louis RH - una specie di. Significa che un'eccezione, se non gestita, risalirà la catena di chiamate attraverso ogni funzione chiamante fino a quando non sarà gestita.
Oded

1
@Louis RH non completamente, ciò significherebbe che devi catturare l'eccezione almeno in te Main per compilare il codice. Poiché C # non conosce le eccezioni verificate, spetta a te intercettarle, altrimenti arriveranno nel runtime e interromperanno il codice.
Johannes Wachter

1
@jwatcher: un metodo principale può anche avere una clausola di lancio.
Louis Rhys

4
@AshishKamble - eh. Questione di opinione. La gestione delle eccezioni è diversa in .NET. Non dare per scontato di sapere cosa è "meglio".
Oded

105

L'operatore sta chiedendo l' equivalente in C # della throwsclausola di Java, non la throwparola chiave. Viene utilizzato nelle firme dei metodi in Java per indicare che è possibile lanciare un'eccezione controllata.

In C # non esiste un equivalente diretto di un'eccezione controllata da Java. C # non ha una clausola di firma del metodo equivalente.

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

si traduce in

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

30

Sì, questo è un vecchio thread, tuttavia trovo spesso vecchi thread quando cerco risposte su Google, quindi ho pensato di aggiungere qualcosa di utile che ho trovato.

Se si utilizza Visual Studio 2012, è disponibile uno strumento integrato che può essere utilizzato per consentire un livello IDE "lanci" equivalente.

Se si utilizzano i commenti della documentazione XML , come menzionato sopra, è possibile utilizzare il tag <exception> per specificare il tipo di eccezione generata dal metodo o dalla classe, nonché informazioni su quando o perché viene generata.

esempio:

    /// <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);
    }

4
OP, questa è la tua risposta. Immagino, ma throwsprobabilmente JAVA non significa nulla per il runtime, a parte essere informativo per lo sviluppatore. Allo stesso modo, ciò che @mvanella ha sottolineato qui è il modo in cui C # fa esattamente lo stesso. Presumo che tu sappia già che questa "documentazione xml" ha uno scopo più significativo. So che questo thread è vecchio.
Hari Lubovac

In realtà, Java non mostra eccezioni a meno che non sia esplicitamente specificato in una throwsclausola o lanciato da un throwcomando. Ciò significa che se si verifica un'eccezione RunTimeException e non viene gestita nello stesso metodo in cui si verifica, l'esecuzione si interromperà qui.
Pedro Lima

18

Ecco una risposta a una domanda simile che ho appena trovato su bytes.com :

La risposta breve è no. Non sono presenti eccezioni controllate in C #. Il progettista del linguaggio discute questa decisione in questa intervista:

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

Il più vicino che puoi ottenere è usare i tag nella tua documentazione XML e distribuire i documenti generati da NDoc con il tuo codice / assembly in modo che altre persone possano vedere quali eccezioni lanci (che è esattamente ciò che fa MS nella documentazione MSDN). Non puoi fare affidamento sul compilatore per informarti sulle eccezioni non gestite, tuttavia, come potresti essere abituato in java.


7

Dopo aver esaminato la maggior parte delle risposte qui, vorrei aggiungere un paio di pensieri.

  1. Affidarsi ai commenti della documentazione XML e aspettarsi che altri facciano affidamento è una scelta sbagliata. La maggior parte del codice C # che ho incontrato non documenta i metodi in modo completo e coerente con i commenti della documentazione XML. E poi c'è il problema più grande che senza eccezioni controllate in C #, come potresti documentare tutte le eccezioni lanciate dal tuo metodo allo scopo del tuo utente API per sapere come gestirle tutte individualmente? Ricorda, conosci solo quelli che ti lanci con la parola chiave throw nella tua implementazione. Le API che stai utilizzando all'interno dell'implementazione del tuo metodo potrebbero anche generare eccezioni che non conosci perché potrebbero non essere documentate e non le stai gestendo nella tua implementazione, quindi esploderanno di fronte al chiamante del tuo metodo. In altre parole,

  2. Andreas ha collegato un'intervista con Anders Hejlsberg nelle risposte qui sul motivo per cui il team di progettazione C # ha deciso di non verificare le eccezioni. La risposta definitiva alla domanda originale è nascosta in quell'intervista:

I programmatori proteggono il loro codice scrivendo finalmente try è ovunque, quindi torneranno indietro correttamente se si verifica un'eccezione, ma in realtà non sono interessati a gestire le eccezioni.

In altre parole, nessuno dovrebbe essere interessato a quale tipo di eccezione ci si può aspettare per una particolare API poiché le catturerete sempre tutte ovunque. E se vuoi davvero preoccuparti di eccezioni particolari, come gestirle dipende da te e non da qualcuno che definisce una firma del metodo con qualcosa come la parola chiave Java throws, forzando una particolare gestione delle eccezioni su un utente API.

-

Personalmente, sono combattuto qui. Sono d'accordo con Anders che l'aver controllato le eccezioni non risolve il problema senza aggiungere nuovi problemi diversi. Proprio come con i commenti della documentazione XML, raramente vedo il codice C # con tutto racchiuso in blocchi di prova finalmente. Mi sembra che questa sia davvero la tua unica opzione e qualcosa che sembra una buona pratica.


3

In realtà non aver controllato le eccezioni in C # può essere considerato un bene o un male.

Io stesso lo considero una buona soluzione poiché le eccezioni verificate forniscono i seguenti problemi:

  1. Eccezioni tecniche che trapelano al livello aziendale / dominio perché non è possibile gestirle correttamente a basso livello.
  2. Appartengono alla firma del metodo che non sempre gioca bene con il design delle API.

Per questo motivo nella maggior parte delle applicazioni più grandi vedrai spesso il seguente schema quando si verificano eccezioni selezionate:

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

Il che significa essenzialmente emulare il modo in cui C # /. NET gestisce tutte le eccezioni.


Non riesco a immaginare come le eccezioni controllate si mescolerebbero con le lambda!
Gabe

@Gabe: sono sicuro che potresti inventare qualche concetto che ti permetta di mescolarli, ma come ho detto, le eccezioni controllate sono in Java anche per lo più non sono buone pratiche, specialmente nelle applicazioni più complesse. Quindi è bene che non siano presenti in C #.
Johannes Wachter

3

Stai chiedendo di questo:

Rilanciare un'eccezione

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

o

static void Main() 
    {
        string s = null;

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

        Console.Write("The string s is null"); // not executed
    }

3
+1 per l'utilizzo throw. Usandolo, la traccia dello stack non andrà persa.
Giuseppe Accaputo

2

Ci sono alcune fugaci somiglianze tra .Net CodeContract EnsuresOnThrow<>e il throwsdescrittore java , in quanto entrambi possono segnalare al chiamante come il tipo di eccezione che potrebbe essere sollevata da una funzione o da un metodo, sebbene ci siano anche grandi differenze tra il 2:

  • EnsuresOnThrow<>va oltre la semplice dichiarazione di quali eccezioni possono essere lanciate, ma stabilisce anche le condizioni in cui è garantito che vengano lanciate - questo può essere un codice abbastanza oneroso nel metodo chiamato se la condizione di eccezione non è banale da identificare. Java throwsfornisce un'indicazione di quali eccezioni potrebbero essere lanciate (cioè IMO il focus in .Net è all'interno del metodo che si contrae per provare il throw, mentre in Java il focus si sposta sul chiamante per riconoscere la possibilità dell'eccezione).
  • .Net CC non fa la distinzione tra eccezioni selezionate e non selezionate che Java ha, sebbene la sezione 2.2.2 del manuale CC menziona

"utilizza postcondizioni eccezionali solo per quelle eccezioni che un chiamante dovrebbe aspettarsi come parte dell'API"

  • In .Net il chiamante può determinare se fare o meno qualcosa con l'eccezione (ad esempio disabilitando i contratti). In Java, il chiamante deve fare qualcosa , anche se aggiunge un throwsper la stessa eccezione sulla sua interfaccia.

Manuale dei contratti di codice qui


0

Se lo scopo del metodo c # è di generare solo un'eccezione (come dice il tipo di ritorno js), consiglierei di restituire quell'eccezione. Vedi l'esempio sotto:

    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;
    }

0

Per coloro che si chiedono, non è nemmeno necessario definire cosa catturare per passarlo al metodo successivo. Nel caso in cui desideri gestire tutti gli errori in un thread principale, puoi semplicemente catturare tutto e trasmetterlo in questo modo:

try {
    //your code here
}
catch {
    //this will throw any exceptions caught by this try/catch
    throw;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.