Wie verwende ich ein Schlüsselwort im Java-Stil in C #?

89

In Java throwsermöglicht das Schlüsselwort einer Methode, zu deklarieren, dass sie eine Ausnahme nicht alleine behandelt, sondern sie an die aufrufende Methode abgibt.

Gibt es ein ähnliches Schlüsselwort / Attribut in C #?

Wenn es kein Äquivalent gibt, wie können Sie den gleichen (oder einen ähnlichen) Effekt erzielen?

Louis Rhys
quelle

Antworten:

75

In Java müssen Sie entweder eine Ausnahme behandeln oder die Methode als eine markieren, die sie mit dem throwsSchlüsselwort auslösen kann.

C # hat dieses oder ein gleichwertiges Schlüsselwort nicht, wie in C #. Wenn Sie keine Ausnahme behandeln, sprudelt es, bis es abgefangen wird, oder wenn es nicht abgefangen wird, wird das Programm beendet.

Wenn Sie damit umgehen möchten, können Sie Folgendes tun:

try
{
  // code that throws an exception
}
catch(ArgumentNullException ex)
{
  // code that handles the exception
  throw;
}
Oded
quelle
1
"es wird sprudeln" bedeutet dies, dass dies allen Methoden entspricht, die eine Throws-Klausel in Java haben?
Louis Rhys
1
@ Louis RH - irgendwie. Dies bedeutet, dass eine Ausnahme, wenn sie nicht behandelt wird, die Aufrufkette durch jede aufrufende Funktion führt, bis sie behandelt wird.
Oded
1
@ Louis RH nicht vollständig, das würde bedeuten, dass Sie die Ausnahme zumindest in Ihrem Main abfangen mussten, um den Code zu kompilieren. Da C # keine geprüften Ausnahmen kennt, liegt es an Ihnen, sie abzufangen, da sie sonst nur zur Laufzeit landen und Ihren Code unterbrechen.
Johannes Wachter
1
@jwatcher: Eine Hauptmethode kann auch eine throw-Klausel haben.
Louis Rhys
4
@ AshishKamble - wie. Ansichtssache. Die Ausnahmebehandlung unterscheidet sich in .NET. Gehen Sie nicht davon aus, dass Sie wissen, was "besser" ist.
Oded
105

Die Operation fragt nach dem C # -Äquivalent der Java- throwsKlausel - nicht nach dem throwSchlüsselwort. Dies wird in Methodensignaturen in Java verwendet, um anzuzeigen, dass eine aktivierte Ausnahme ausgelöst werden kann.

In C # gibt es kein direktes Äquivalent zu einer von Java geprüften Ausnahme. C # hat keine äquivalente Methodensignaturklausel.

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

wird übersetzt in

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

Ja, dies ist ein alter Thread, aber ich finde häufig alte Threads, wenn ich Antworten google, also dachte ich, ich würde etwas Nützliches hinzufügen, das ich gefunden habe.

Wenn Sie Visual Studio 2012 verwenden, gibt es ein integriertes Tool, mit dem eine IDE-Ebene "Würfe" -Äquivalente ermöglicht werden kann.

Wenn Sie wie oben erwähnt XML-Dokumentationskommentare verwenden , können Sie mit dem Tag <exception> den von der Methode oder Klasse ausgelösten Ausnahmetyp sowie Informationen darüber angeben, wann oder warum sie ausgelöst werden.

Beispiel:

    /// <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
quelle
4
OP, das ist deine Antwort. Ich vermute, aber JAVA throwsbedeutet wahrscheinlich nichts für die Laufzeit, abgesehen davon, dass es für den Entwickler informativ ist. Ebenso hat @mvanella hier darauf hingewiesen, dass C # genau dasselbe tut. Ich gehe davon aus, dass Sie bereits wissen, dass diese "XML-Dokumentation" einen wichtigeren Zweck hat. Ich weiß, dass dieser Thread alt ist.
Hari Lubovac
Tatsächlich sprudelt Java keine Ausnahmen in die Luft, es sei denn, es wird explizit in einer throwsKlausel angegeben oder von einem throwBefehl ausgelöst . Das heißt, wenn eine RunTimeException auftritt und nicht in derselben Methode behandelt wird, in der sie auftritt, wird die Ausführung dort gestoppt.
Pedro Lima
18

Hier ist eine Antwort auf eine ähnliche Frage, die ich gerade auf bytes.com gefunden habe :

Die kurze Antwort lautet nein. In C # gibt es keine aktivierten Ausnahmen. Der Designer der Sprache diskutiert diese Entscheidung in diesem Interview:

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

Am nächsten können Sie die Tags in Ihrer XML-Dokumentation verwenden und von NDoc generierte Dokumente mit Ihrem Code / Ihren Assemblys verteilen, damit andere Personen sehen können, welche Ausnahmen Sie auslösen (genau das tun MS in der MSDN-Dokumentation). Sie können sich jedoch nicht darauf verlassen, dass der Compiler Sie über nicht behandelte Ausnahmen informiert, wie Sie es in Java gewohnt sind.

Andreas Dolk
quelle
7

Nachdem ich die meisten Antworten hier durchgesehen habe, möchte ich ein paar Gedanken hinzufügen.

  1. Sich auf Kommentare zur XML-Dokumentation zu verlassen und zu erwarten, dass andere sich darauf verlassen, ist eine schlechte Wahl. Der meiste C # -Code, auf den ich gestoßen bin, dokumentiert Methoden nicht vollständig und konsistent mit XML-Dokumentationskommentaren. Und dann gibt es das größere Problem: Wie können Sie ohne aktivierte Ausnahmen in C # alle Ausnahmen dokumentieren, die Ihre Methode auslöst, damit Ihr API-Benutzer weiß, wie sie alle einzeln behandelt werden? Denken Sie daran, dass Sie nur diejenigen kennen, die Sie in Ihrer Implementierung mit dem Schlüsselwort throw werfen. APIs, die Sie in Ihrer Methodenimplementierung verwenden, lösen möglicherweise auch Ausnahmen aus, von denen Sie nichts wissen, da sie möglicherweise nicht dokumentiert sind und Sie sie in Ihrer Implementierung nicht behandeln, sodass sie angesichts des Aufrufers von Ihnen in die Luft jagen Methode. Mit anderen Worten,

  2. Andreas hat in den Antworten hier ein Interview mit Anders Hejlsberg verknüpft, warum sich das C # -Design-Team gegen geprüfte Ausnahmen entschieden hat. Die endgültige Antwort auf die ursprüngliche Frage ist in diesem Interview verborgen:

Die Programmierer schützen ihren Code, indem sie versuchen, endlich überall zu schreiben, damit sie korrekt zurückkehren, wenn eine Ausnahme auftritt, aber sie sind nicht wirklich daran interessiert, die Ausnahmen zu behandeln.

Mit anderen Worten, niemand sollte sich dafür interessieren, welche Art von Ausnahme für eine bestimmte API zu erwarten ist, da Sie immer alle überall abfangen werden. Und wenn Sie sich wirklich um bestimmte Ausnahmen kümmern möchten, liegt es an Ihnen, wie Sie mit ihnen umgehen, und nicht an jemandem, der eine Methodensignatur mit einem Schlüsselwort wie Java definiert, das einem API-Benutzer eine bestimmte Ausnahmebehandlung aufzwingt.

- -

Persönlich bin ich hier hin und her gerissen. Ich stimme Anders zu, dass das Überprüfen von Ausnahmen das Problem nicht löst, ohne neue, andere Probleme hinzuzufügen. Genau wie bei den Kommentaren zur XML-Dokumentation sehe ich selten C # -Code mit allem, was in try finally-Blöcken eingeschlossen ist. Es fühlt sich für mich so an, als wäre dies in der Tat Ihre einzige Option und etwas, das als gute Praxis erscheint.

Tobias
quelle
3

Das Fehlen von geprüften Ausnahmen in C # kann als gut oder schlecht angesehen werden.

Ich selbst halte es für eine gute Lösung, da geprüfte Ausnahmen folgende Probleme aufwerfen:

  1. Technische Ausnahmen, die in die Geschäfts- / Domänenschicht gelangen, weil Sie sie auf niedriger Ebene nicht richtig handhaben können.
  2. Sie gehören zur Methodensignatur, die beim API-Design nicht immer gut funktioniert.

Aus diesem Grund wird in den meisten größeren Anwendungen häufig das folgende Muster angezeigt, wenn diese Option aktiviert ist. Ausnahmen treten auf:

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

Dies bedeutet im Wesentlichen, die Art und Weise zu emulieren, wie C # /. NET alle Ausnahmen behandelt.

Johannes Wachter
quelle
Ich kann mir nicht vorstellen, wie sich geprüfte Ausnahmen mit Lambdas vermischen würden!
Gabe
@Gabe: Ich bin sicher, Sie könnten ein Konzept entwickeln, mit dem Sie sie mischen können, aber wie gesagt, überprüfte Ausnahmen sind in Java meistens auch keine gute Praxis, insbesondere in komplexeren Anwendungen. Es ist also gut, dass sie in C # nicht da sind.
Johannes Wachter
3

Sie fragen danach:

Eine Ausnahme erneut auslösen

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

oder

static void Main() 
    {
        string s = null;

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

        Console.Write("The string s is null"); // not executed
    }
Pranay Rana
quelle
3
+1 für die Verwendung throw. Durch die Verwendung geht der Stack-Trace nicht verloren.
Giuseppe Accaputo
2

Es gibt einige flüchtige Ähnlichkeiten zwischen dem .Net CodeContract EnsuresOnThrow<>und dem Javathrows Deskriptor, da beide dem Aufrufer als Ausnahmetyp signalisieren können, der von einer Funktion oder Methode könnte, obwohl es auch große Unterschiede zwischen den beiden gibt:

  • EnsuresOnThrow<>geht über die bloße Angabe, welche Ausnahmen ausgelöst werden können, hinaus, legt aber auch die Bedingungen fest, unter denen sie garantiert ausgelöst werden - dies kann in der aufgerufenen Methode ein ziemlich lästiger Code sein, wenn die Ausnahmebedingung nicht trivial zu identifizieren ist. Java throwsgibt einen Hinweis darauf, welche Ausnahmen ausgelöst werden könnten (dh IMO liegt der Fokus in .Net innerhalb der Methode, die sich zum Nachweis der Verträge zusammenziehtthrow , während sich in Java der Fokus auf den Aufrufer verlagert, um die Möglichkeit der Ausnahme anzuerkennen).
  • .Net CC unterscheidet nicht zwischen geprüften und nicht geprüften Ausnahmen, die Java hat, obwohl im CC-Handbuch in Abschnitt 2.2.2 erwähnt wird

"Verwenden Sie außergewöhnliche Nachbedingungen nur für die Ausnahmen, die ein Anrufer als Teil der API erwarten sollte."

  • In .Net kann der Anrufer festlegen, ob mit der Ausnahme etwas unternommen werden soll oder nicht (z. B. durch Deaktivieren von Verträgen). In Java muss der Aufrufer etwas tun , auch wenn er throwsauf seiner Schnittstelle eine Ausnahme für dieselbe Ausnahme hinzufügt .

Code Vertragshandbuch hier

StuartLC
quelle
0

Wenn die c # -Methode nur eine Ausnahme auslösen soll (wie der Rückgabetyp js sagt), würde ich empfehlen, nur diese Ausnahme zurückzugeben. Siehe das folgende Beispiel:

    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;
    }
EINGESTEHEN
quelle
0

Für diejenigen, die sich fragen, müssen Sie nicht einmal definieren, was Sie fangen, um es an die nächste Methode weiterzugeben. Wenn Sie alle Fehler in einem Hauptthread behandeln möchten, können Sie einfach alles abfangen und wie folgt weitergeben:

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