2009-05-29 5 views
9

Gibt es Speicherverluste, wenn ich eine Ausnahme von einem Konstruktor wie folgt auslösen?Auslösen von Ausnahmen von einem Konstruktor in. NET

Werden die fehlerhaften Objekte vom Garbage Collector erfasst?

+0

kaum verwandt, aber nützlicher Tipp: Seien Sie vorsichtig über Ausnahmen in Konstrukteuren von Kontrollen geworfen. Es kann den Designer für die Kontrolle/Form brechen. Ich habe es geschafft, indem ich eine Initialise() -Methode habe und diese extern anrufe (aber ich mag es nicht). –

Antwort

23

Im Allgemeinen ist dies sicher aus der Perspektive nicht ausleckenden Speicher. Das Auslösen von Ausnahmen aus einem Konstruktor ist jedoch gefährlich, wenn Sie nicht verwaltete Ressourcen im Typ zuweisen. Nehmen Sie das folgende Beispiel

public class Foo : IDisposable { 
    private IntPtr m_ptr; 
    public Foo() { 
    m_ptr = Marshal.AllocHGlobal(42); 
    throw new Exception(); 
    } 
    // Most of Idisposable implementation ommitted for brevity 
    public void Dispose() { 
    Marshal.FreeHGlobal(m_ptr); 
    } 
} 

Diese Klasse wird Speicher jedes Mal, wenn Sie versuchen zu erstellen, Speicher verlieren, auch wenn Sie einen Verwendungsblock verwenden. Zum Beispiel verliert dies Speicher.

using (var f = new Foo()) { 
    // Won't execute and Foo.Dispose is not called 
} 
+0

Es muss klargestellt werden, dass nicht nur der Rumpf der using-Anweisung nicht ausgeführt wird ... sondern die .Dispose() -Methode von Foo nicht aufgerufen wird, weil keine Instanz zum Aufruf von .Dispose() erstellt wurde. – jrista

+0

@jrista aktualisiert – JaredPar

+0

Ich bin ernsthaft zu spät zur Party hier, aber würde nicht versuchen - endlich im Konstruktor beheben das ohne Problem? – Gusdor

2

Ja, der Garbage Collector wird die verwalteten Ressourcen zurückfordern, die bereits im Objekt zugewiesen wurden. Wenn Sie nicht verwaltete Ressourcen initialisiert haben, müssen Sie diese auf die übliche Weise selbst bereinigen.

1

Es hängt davon ab, welche anderen Ressourcen Sie erworben haben, bevor die Ausnahme thorwn ist. Ich denke nicht, dass das Auslösen von Exceptions in einem Konstruktor großartig ist, aber sie in Finalizer oder dispose() zu werfen ist viel viel schlimmer.

+2

"werfen sie in Finalizer oder entsorgen() ist viel viel schlimmer.". Es kann akzeptabel sein, Dispose auszulösen - zum Beispiel wird FileStream werfen, wenn es den Stream nicht löschen kann (z. B. aufgrund eines Netzwerkfehlers). Vermeiden Sie zu werfen, wenn Sie können, aber tun Sie es, wenn Sie müssen. Im Falle von FileStream wäre das Verschlucken der Ausnahme viel gefährlicher als das Werfen, da dies dem Aufrufer den Eindruck vermitteln würde, dass die Datei erfolgreich geschrieben wurde. – Joe

4

Komisch, weil ich erst gestern mit einer similar question geholfen habe.

Es ist ein größeres Problem, wenn Sie einen abgeleiteten Typ haben, weil einige Teile des abgeleiteten Typs initialisiert werden, andere jedoch nicht. Aus Speicherperspektive spielt es keine Rolle, denn der Müllsammler weiß, wo sich was befindet. Aber wenn Sie nicht verwaltete Ressourcen (IDisposable implementieren) haben, können die Dinge trübe werden.

9

Das Auslösen von Ausnahmen von einem Konstruktor sollte in Ordnung sein, wenn Sie keine nicht verwalteten Ressourcen erstellt haben. Wenn Sie jedoch im Konstruktor nicht verwaltete Ressourcen erstellen, sollte der gesamte Rumpf dieses Konstruktors, einschließlich der Würfe, in eine try/catch-Schleife eingeschlossen werden. JaredPar das große Beispiel zu klauen:

public class Foo : IDisposable { 
    private IntPtr m_ptr; 
    public Foo() { 
    try 
    { 
     m_ptr = Marshal.AllocHGlobal(42); 
     throw new Exception(); 
    } 
    catch 
    { 
     Dispose(); 
     throw; 
    } 
    } 
    // Most of Idisposable implementation ommitted for brevity 
    public void Dispose() { 
    Marshal.FreeHGlobal(m_ptr); 
    } 
} 

Die folgende funktionieren würde jetzt:

using (var f = new Foo()) { 
    // Won't execute, but Foo still cleans itself up 
} 
Verwandte Themen