2009-09-28 2 views
39

In meiner Anwendung muss ich eine Ausnahme auslösen, wenn eine Eigenschaft einer bestimmten Klasse null oder leer ist (falls es eine Zeichenfolge ist). Ich bin nicht sicher, was die beste Ausnahme in diesem Fall ist. Ich würde es hassen, eine neue Ausnahme zu erstellen, und ich bin mir nicht sicher, ob ArgumentNullException in diesem Fall geeignet ist.Welcher Ausnahmetyp wird verwendet, wenn eine Eigenschaft nicht null sein kann?

Sollte ich eine neue Ausnahme erstellen oder es gibt eine Ausnahme, die ich verwenden kann?

Ich habe nichts dagegen, eine ApplicationException zu werfen.

+0

Denken Sie auch an Eigenschaften sind syntaktische gezuckerte Methoden. – Dykam

+0

Eine verwandte interessante Diskussion: http://stackoverflow.com/questions/1488472/best-practices-throwing-exceptions-from-properties – Joren

Antwort

65

Die MSDN guidelines for standard exceptions Staaten:

Gebrauchswert für den Namen des impliziten Wertparameter der Eigenschaft Setter tun.

Das folgende Codebeispiel zeigt eine Eigenschaft, die eine Ausnahme, wenn der Anrufer übergibt ein Null-Argument wirft.

public IPAddress Address 
{ 
    get 
    { 
     return address; 
    } 
    set 
    { 
     if(value == null) 
     { 
      throw new ArgumentNullException("value"); 
     } 
     address = value; 
    } 
} 

Zusätzlich kann die MSDN guidelines for property design sagen:

Vermeiden Sie werfen Ausnahmen von Eigenschaft Getter.

Eigenschaftsgetter sollten einfach sein Operationen ohne irgendwelche Vorbedingungen. Wenn ein Getter eine Ausnahme auslöst, sollten Sie die Methode in Betracht ziehen, die Eigenschaft zu umzuwandeln. Diese Empfehlung gilt nicht für Indexer . Indexer können Ausnahmen aufgrund ungültiger Argumente werfen.

Es ist zulässig und akzeptabel, Ausnahmen von einem Property Setter zu werfen.

So ArgumentNullException in dem Setter auf null und ArgumentException auf der leeren Zeichenkette werfen, und in dem Getter nichts tun. Da der Setter nur das Backing-Feld aufruft und Sie Zugriff auf das Backing-Feld haben, können Sie leicht sicherstellen, dass es keinen ungültigen Wert enthält. Der Getterwurf ist dann sinnlos. Dies könnte jedoch ein guter Ort sein, um Debug.Assert zu verwenden.

Wenn Sie wirklich keinen geeigneten Standard zur Verfügung stellen können, dann nehme ich Dir drei Möglichkeiten:

  1. einfach zurückgeben, was auch immer in der Eigenschaft und Dokument dieses Verhalten im Rahmen des Nutzungsvertrages ist. Lassen Sie den Anrufer damit umgehen. Sie können auch einen gültigen Wert im Konstruktor anfordern. Dies kann jedoch für Ihre Anwendung völlig ungeeignet sein.

  2. Ersetzen Sie die Eigenschaft durch Methoden: Eine Setter-Methode, die beim Übergeben einen ungültigen Wert auslöst, und eine Getter-Methode, die InvalidOperationException auslöst, wenn der Eigenschaft nie ein gültiger Wert zugewiesen wurde.

  3. Werfen Sie InvalidOperationException aus dem Getter, da Sie in Betracht ziehen könnten "Eigenschaft wurde nie zugewiesen" einen ungültigen Zustand. Obwohl Sie normalerweise nicht von Gettern werfen sollten, könnte dies ein guter Grund sein, eine Ausnahme zu machen.

Wenn Sie Optionen 2 oder 3 wählen, sollten Sie umfassen auch eine TryGet- Methode, die eine bool zurückgibt, die, wenn die Eigenschaft anzeigt, auf einen gültigen Wert gesetzt worden ist, und wenn wieder so diesen Wert in einem out Parameter . Sonst erzwingt man Anrufer, mit einem InvalidOperationException fertig zu werden, es sei denn, sie haben zuvor die Eigenschaft selbst eingestellt und wissen somit, dass sie nicht werfen wird. Vergleichen Sie int.Parse gegenüber int.TryParse.

Ich würde vorschlagen, Option 2 mit der TryGet-Methode zu verwenden. Es verletzt keine Richtlinien und stellt minimale Anforderungen an den aufrufenden Code.


Über die anderen Vorschläge
ApplicationException ist viel zu allgemein. ArgumentException ist ein bisschen zu allgemein für null, aber ansonsten gut.MSDN docs again:

Sie die spezifischste (die meisten abgeleitet) Ausnahme auslösen, die geeignet ist. Wenn beispielsweise eine Methode ein Null-Argument (Nothing in Visual Basic) empfängt, sollte stattdessen System.ArgumentNullException des Basistyps System.ArgumentException ausgelöst werden.

In der Tat sollten Sie nicht ApplicationException verwenden bei allen (docs): System.Exception Klasse statt der T: System.ApplicationException Klasse

Sie benutzerdefinierte Ausnahmen von der T abzuleiten.

Ursprünglich wurde angenommen, dass benutzerdefinierte Ausnahmen von der ApplicationException-Klasse abgeleitet werden sollten. Es wurde jedoch nicht gefunden, dass dies einen signifikanten Wert hinzufügt. Weitere Informationen finden Sie unter Bewährte Methoden für die Behandlung von Ausnahmen.

InvalidOperationException ist nicht beabsichtigt, für wenn die Argumente auf eine Methode oder Eigenschaft ungültig sind, aber für die, wenn der Betrieb als Ganzes ist ungültig (docs). Es soll nicht aus den Setter geworfen werden:

Führen Sie eine System.InvalidOperationException Ausnahme, wenn in einem ungeeigneten Zustand werfen. System.InvalidOperationException sollte ausgelöst werden, wenn ein Eigenschaftensatz oder ein Methodenaufruf angesichts des aktuellen Status des Objekts nicht geeignet ist. Wenn Sie beispielsweise in einen System.IO.FileStream schreiben, der zum Lesen geöffnet wurde, sollte eine System.InvalidOperationException-Ausnahme ausgelöst werden.

übrigens InvalidOperationException ist, wenn die Operation ungültig ist für den aktuellen Zustand des Objekts. Wenn die Operation für die gesamte Klasse immer ungültig ist, sollten Sie NotSupportedException verwenden.

+0

@Joren, @Vadim gibt an, dass er einen Standard-Instruktor benötigt und für dieses Feld keinen angemessenen Standardwert hat. Daher reicht es nicht aus, den Setter zu überwachen, um sein Szenario zu erstellen. – bdukes

+0

Sie haben Recht, ich werde meine Antwort bearbeiten. – Joren

+0

@ Joren, ausgezeichnete Antwort. – Vadim

1

Setzt der Konstruktor ihn auf einen Nicht-Null-Wert? Wenn ja, würde ich einfach ArgumentNullException vom Setzer werfen.

4

Ich würde eine InvalidOperationException werfen. MSDN sagt es "wird ausgelöst, wenn ein Methodenaufruf für den aktuellen Status des Objekts ungültig ist".

+1

Ich denke nicht, dass das für dieses Szenario geeignet ist. InvalidOperationException sollte nur verwendet werden, wenn das aufgerufene Objekt ungültig ist. In diesem Fall ist das aufgerufene Objekt 100% gültig, es ist das Argument der Methode, das ungültig ist. – JaredPar

+2

Sie würden "InvalidOperationException" auslösen, wenn das Objekt in einem Zustand wäre, in dem die Verwendung des Eigenschaftensetters überhaupt nicht möglich wäre. Das heißt, die * Operation * selbst ist ungültig. Die MSDN-Dokumentation gibt das Beispiel "Schreiben zu einem' System.IO.FileStream ', das für das Lesen geöffnet wurde". – Joren

+0

Ich nehme an, wir kennen nicht das genaue Szenario von dem, was aufgerufen wird. Ich arbeite unter der Annahme, dass wir eine Methode einer Klasse aufrufen und versuchen, eine Eigenschaft dieser Klasse innerhalb der Methode zu verwenden. In diesem Fall ist das Objekt für die Methode, die aufgerufen wird, ungültig (da die Eigenschaft festgelegt werden muss, bevor die Methode aufgerufen werden kann). Es sieht so aus, als ob @ JaredPar das Szenario berücksichtigt, in dem eine Eigenschaft in einem Argument nicht initialisiert wird. In diesem Fall macht sein Vorschlag von "ArgumentException" am meisten Sinn. – bdukes

2

Nun, es ist kein Argument, wenn Sie eine Eigenschaft einer Klasse referenzieren. Daher sollten Sie ArgumentException oder ArgumentNullException nicht verwenden.

NullReferenceException würde passieren, wenn Sie nur Dinge in Ruhe lassen, also nehme ich an, das ist nicht, was Sie suchen.

Daher wäre die Verwendung von ApplicationExeption oder InvalidOperationException wahrscheinlich die beste Lösung. Achten Sie darauf, eine aussagekräftige Zeichenfolge anzugeben, um den Fehler zu beschreiben.

+1

Ich bin mir ziemlich sicher, dass es in .NET Framework Klassen gibt, die ArgumentException vom Setter einer Eigenschaft werfen. Ich kann mich nicht mehr genau erinnern, aber ich erinnere mich, dass ich darauf gestoßen bin. Man könnte argumentieren, dass es nicht "richtig" sei, aber unabhängig davon, ob der Rahmen den Präzedenzfall geschaffen hat. – Tinister

2

Es ist durchaus angemessen, ArgumentNullException zu werfen, wenn jemand versucht, null zuweisen.

Eine Eigenschaft sollte niemals eine Leseoperation auslösen.

+0

Woher kommt die Idee, dass eine Eigenschaft niemals eine Leseoperation auslösen sollte? Es kann sicherlich leicht genug passieren. –

+1

@John Ich denke nicht, dass sein Punkt war, dass es nicht kann, aber nur, dass es nicht sollte. –

+1

@ John Fisher: Cwalina, Krzystof und Brad Abrams: "Framework-Design-Richtlinien. Konventionen, Idiome und Patterns für wiederverwendbare .Net-Bibliotheken", Addison-Wesley, 2006. p. 121 - unter anderen Quellen. –

1

Wenn das Problem ist, dass ein Mitglied eines Arguments, und nicht das Argument selbst, null ist, dann denke ich, die beste Wahl ist die generische . ArgumentNullException funktioniert hier nicht, weil das Argument tatsächlich nicht null ist. Stattdessen brauchen Sie den generischen "etwas ist falsch mit Ihrem Argument" -Ausnahmetyp.

Eine detaillierte Nachricht für den Konstruktor würde hier

+0

Was meinst du "eine Detailnachricht für den Konstruktor"? Ich muss einen Standardkonstruktor haben. – Vadim

+0

@Vadim ein ausführlicher Grund, warum die Argumentausnahme ausgelöst wird. Zum Beispiel "Property Blah von Parameter foo muss nicht null sein" – JaredPar

+0

@Vadim, er bezieht sich auf den Konstruktor der Exception, nicht den Konstruktor Ihres Objekts. – bdukes

1

sehr sinnvoll sein, wenn es nicht null oder leer sein kann, haben Ihre Setter nicht null oder leer Werte erlauben, oder ein Argument werfen, wenn das der Fall ist.

Außerdem muss die Eigenschaft im Konstruktor festgelegt werden.

Auf diese Weise erzwingen Sie einen gültigen Wert, anstatt später zurückzukommen und sagen, dass Sie den Kontostand nicht bestimmen können, da das Konto nicht festgelegt ist.

Aber ich würde Bduke's Antwort zustimmen.

+1

Ich muss Standardkonstruktor haben. – Vadim

+0

Sie können nicht einen gültigen Standardwert setzen Ich nehme es im Konstruktor? –

+1

Leider kann ich kein Ratespiel spielen. Ich habe keine Ahnung, welcher Wert zur Laufzeit eingestellt werden sollte. – Vadim

1

Es gibt einen Präzedenzfall, um die Interpretation von ArgumentNullException auf die Bedeutung "string argument ist null oder leer" zu erweitern: System.Windows.Clipboard.SetText löst in diesem Fall eine ArgumentNullException aus.

So würde ich nichts falsch mit der Verwendung dieser eher als die allgemeinere ArgumentException in Ihrem Property Setter sehen, vorausgesetzt, Sie dokumentieren es.

0

Werfen Sie einfach was auch immer, solange die Fehlermeldung für einen Entwickler hilfreich ist. Diese Klasse von Ausnahmen sollte niemals außerhalb der Entwicklung passieren.

Verwandte Themen