2009-09-23 13 views
34

Wie kann ich die InnerException Eigenschaft eines Exception Objekts festlegen, während ich im Konstruktor dieses Objekts bin? Dies läuft darauf hinaus, das Hintergrundfeld einer Eigenschaft zu finden und festzulegen, die keinen Setter hat.Set InnerException von .NET Exception-Objekt

BTW: Ich habe dies gesehen (http://evain.net/blog/articles/2009/05/01/getting-the-field-backing-a-property-using-reflection), aber auf der Suche nach nicht-IL-basierten Lösung, wenn möglich.

Der Exception-Konstruktor ist der Ort, wo der Ausnahmetyp erstellt wird, so kann ich es nicht nennen die Basisklassenkonstruktor MyException mit(): base (...) usw.

+0

Re die Follow-up; dann (wie ich bereits erwähnt habe) die Typerstellung in einer statischen Methode * ahead * des ctor statt innerhalb des Konstruktorkörpers. –

+1

In meinem Fall macht es mehr Sinn zu kapseln. –

+0

... aber ich nehme Ihren Punkt, ich werde schauen, dies zu einer Fabrik zu machen, um die Reflektionskosten zu vermeiden. –

Antwort

12

Warum können Sie nicht einfach den Konstruktor aufrufen, der InnerException als Parameter verwendet? Wenn aus irgendeinem Grund ist es nicht möglich, ist die dahinter liegende Feld in System.Exception:

private Exception _innerException; 

ich es gefunden Redgate's Reflector mit aus. Mit Reflektion könnte man die innere Ausnahme setzen.

Bearbeiten: In den meisten Fällen ist es keine gute Idee, auf private Felder durch Reflexion zuzugreifen, aber ich weiß nicht genug über NT Fall zu wissen, ob es eine gute oder schlechte Idee ist.

+9

Ich kann mir kein vernünftiges Beispiel vorstellen, bei dem die Reflexion der richtige Weg ist ... –

+0

Es ist sinnvoll für dynamische Szenarien mit Aktivierungen von Exceptions, bei denen die innere Exception nicht im Voraus bekannt sein kann und deshalb nicht an den Konstruktor übergeben werden kann . –

+3

Nein, tut es nicht. Es tut wirklich nicht; Es bricht die Kapselung. Verwenden Sie eine statische Methode in der ': base (SomeMethod (...), ...) Kette. –

7
Exception exceptionWithMoreInfo = new Exception("extra info", ex); 

normale Praxis würde Angenommen, Sie haben eine Ausnahme abgefangen, zu der Sie weitere Informationen hinzufügen möchten, bevor Sie aufblasen.

+1

Dies hilft dir aber nicht im ctor der ausnahme. – Joey

59

Sie legen die innere Ausnahme von der Basis Ctor Aufruf: Ist

public MyException(SomeData data) : base(GetMessage(data), GetInner(data)) {...} 
static Exception GetInner(SomeData data) {...} // <===== your type creation here! 
static string GetMessage(SomeData data) {...} 
1

nicht InnerException:

public MyException(string message, Exception innerException) 
     : base(message, innerException) {...} 

Wenn Sie einen Code ausführen müssen die Ausnahme zu erhalten, verwenden Sie eine statische Methode soll bei Verwendung des Exception(string, Exception) Konstruktors gesetzt werden? Ich denke, es ist von Entwurf, dass Sie nicht die sonst ändern, aber Sie können an den entsprechenden Konstruktor an Bauzeit immer verschieben:

class MyException : Exception { 
    public MyException() 
     : base("foo", new Exception("bar")) 
    { 
     ... 
    } 

    ... 
} 

Ich glaube, Sie sollen nicht immer die Ausnahme Kette in Ihrem Code brechen, da dieser in der Regel führt zu Fehlern, die Sie nie wieder finden werden.

29

Die Exception Klasse verfügt über einen überladenen Konstruktor die innere Ausnahme als Parameter akzeptieren:

Exception exc = new Exception("message", new Exception("inner message")); 

Ist das, was Sie suchen?

+0

Während dies seine Frage nicht direkt beantwortet, antwortet es, wonach die meisten Leute suchten, nach denen gesucht wurde. – rolls

1

Wenn ich Ihre Frage verstehen wollen Sie so etwas wie dies zu tun:

Exception ex = new Exception("test"); 
Exception innerEx = new Exception("inner"); 
ex.GetType().GetField("_innerException", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(ex, innerEx); 

Wenn Sie im Konstruktor eines Objekts sind, die von Exception erbt Sie this anstelle des ersten ex verwenden würde.

Aber das ist möglicherweise nicht der beste Weg, um zu handhaben, was auch immer Sie versuchen zu behandeln.

+0

Was ist falsch mit Ausnahme innerEx = neue Ausnahme ("inner"); Ausnahme ex = new Ausnahme ("test", innerEx); ? –

+0

Er versucht, das Objekt ex, das nicht im Kontext erstellt wurde, zu modifizieren, ich erstelle es nur zum Zweck der Demonstration. Tatsächlich versucht er in diesem Fall, diese Instanz zu modifizieren. – pauloya

+0

+1: Dies beantwortete meine eigene, ziemlich dumme Frage, wie man die innere Ausnahme einer Exception erzwingen kann, was wiederum spaßige Dinge verursacht, wie die ToString() - Methode einen Stapelüberlauf auszulösen. – Brian

1

Verwenden Sie den Redgate-Reflektor, um das Feld zu finden. Ich bezweifle, dass sich die Ausnahme-Implementierung jemals ändern wird ... Aber es ist ein Risiko!

+0

Warum würden Sie das bezweifeln? Welche Grundlage haben Sie für diese Beurteilung? Wenn ich Microsoft wäre, würde ich die Implementierung ändern, nur um Dummköpfe zu ärgern, die auf interne Implementierungsdetails der Klassen anderer Leute angewiesen sind. –

+2

Basiert auf der Menge solcher Details, die sich über die letzten Rahmenupdates geändert haben? –

+1

@John: Gut, dass du nicht für MS arbeitest! – Scooterville

0

Ich weiß, ich bin wirklich zu spät zur Party, aber ich finde, dass das funktioniert.

public class MyException: Exception 
{ 
    public void SetInnerException(Exception exception) 
    { 
     typeof(Exception) 
      .GetField("_innerException", BindingFlags.NonPublic | BindingFlags.Instance) 
      .SetValue(this, exception); 
    } 
} 

Der Trick ist, die tatsächliche Exception Typ des _innerException Feld zu bekommen, und dann die innere Ausnahme Wert für Ihre Klasseninstanz (MyException in diesem Fall).

Dies funktioniert auch für Variablen.

Exception mainException = new Exception(); 
typeof(Exception) 
    .GetField("_innerException", BindingFlags.NonPublic | BindingFlags.Instance) 
    .SetValue(mainException , new Exception("Something bad happened!"));