Frage

Als erster Linie ein C ++ Entwickler das Fehlen von RAII (Resource Acquisition Is Initialization) in Java und .NET hat mich immer gestört. Die Tatsache, dass die Last der Reinigung aus der Klasse Schriftsteller seine Verbraucher bewegt (mittels try finally oder .NET der using Konstrukt ) deutlich schlechter zu sein scheint.

Ich sehe, warum in Java gibt es keine Unterstützung für RAII ist, da alle Objekte auf dem Heap und die Garbage Collector von Natur aus nicht unterstützt deterministische Zerstörung befinden, aber in .NET mit der Einführung von Werttypen (struct) haben wir der (scheinbar) perfekte Kandidat für RAII. Ein Wert, der auf dem Stapel erstellt werden hat einen gut definierte Umfang und C ++ destructor Semantik verwendet werden kann. Allerdings hat die CLR keinen Wert-Typen erlaubt eine destructor zu haben.

Meine zufälligen Suchen gefunden ein Argument, dass, wenn ein Wert vom Typ eingerahmt ist es fällt unter der Zuständigkeit des garbage collector und damit seine Zerstörung wird nicht-deterministisch. Ich glaube, dass dieses Argument nicht stark genug ist, die Vorteile der RAH sind groß genug, um zu sagen, dass ein Wert-Typ mit einem destructor kann nicht verpackt werden (oder als Klassenelement verwendet).

eine lange Geschichte kurz zu machen, meine Frage ist: : gibt es andere Gründe Werttypen können nicht verwendet werden, um die Einführung RAH auf .NET? (Oder denken Sie, mein Argument über RAII offensichtliche Vorteile fehlerhaft sind?)

Edit: Ich darf nicht die Frage klar formuliert haben, da die ersten vier Antworten den Punkt verpasst haben. I wissen über Finalize und seine nicht-deterministischen Eigenschaften, ich weiß über das using Konstrukt und ich fühle mich diese beiden Optionen zu RAH minderwertig sind. using ist eine weitere Sache, die Verbraucher einer Klasse erinnern müssen (wie viele Menschen vergessen, eine StreamReader in einem using Block zu setzen?). Meine Frage ist ein philosophischer über die Sprache Design, warum es so wie es ist und kann sie verbessert werden?

Zum Beispiel mit einem generischen determinis zerstörbaren Wert-Typ kann ich die using und lock Schlüsselwörter redundant (erreichbar von Bibliotheksklassen) machen:

    public struct Disposer<T> where T : IDisposable
    {
        T val;
        public Disposer(T t) { val = t; }
        public T Value { get { return val; } }
        ~Disposer()  // Currently illegal 
        {
            if (val != default(T))
                val.Dispose();
        }
    }

kann ich nicht helfen, aber mit einem apropos Zitat Ende, das ich sah einmal, aber nicht zur Zeit seinen Ursprung finden.

  

Sie können meine deterministische Zerstörung, wenn meine kalte, tote Hand geht out of scope nehmen. - Anon

War es hilfreich?

Lösung

Ein besserer Titel wäre "Warum gibt es keine RAII in C # / VB". C ++ / CLI (Die Entwicklung der Abtreibung, die C Managed wurde ++) hat RAII in dem exakt gleichen Sinne wie C ++. Es ist alles nur Syntax Zucker für den gleichen Abschluss Muster, das der Rest der CLI Sprachen verwenden (Destructors in verwalteten Objekte für C ++ / CLI sind effektiv Finalisern), aber es ist da.

Vielleicht möchten Sie http://blogs.msdn.com /hsutter/archive/2004/07/31/203137.aspx

Andere Tipps

Ausgezeichnete Frage und eine, die mich sehr gestört hat. Es scheint, dass die Vorteile der RAH sind sehr unterschiedlich wahrgenommen. Nach meiner Erfahrung mit .NET, ist das Fehlen von deterministisch (oder zumindest zuverlässig) Ressourcensammlung eine der wichtigsten Nachteile. In der Tat hat mich .NET gezwungen mehrmals ganze Architekturen zu beschäftigen mit nicht verwalteten Ressourcen zu beschäftigen, die Macht (aber vielleicht auch nicht) bedürfen der ausdrücklichen Sammeln. Was natürlich, ist ein großer Nachteil, weil es die Gesamtarchitektur erschwert und lenkt die Aufmerksamkeit des Kunden abseits der zentralen Aspekte.

Brian Harry hat einen schönen Beitrag über die rationalen hier .

Hier ist ein Auszug:

  

Was ist deterministisch Finalisierung und Werttypen (structs)?

     

-------------- Ich habe eine Menge von Fragen zu structs gesehen zu haben   Destruktoren, etc. Dies ist wert   Kommentar. Es gibt eine Vielzahl von   Fragen, warum einige Sprachen nicht   haben sie.

     

(1) Zusammensetzung - Sie müssen Sie nicht geben   deterministische Lebensdauer in der allgemeinen   Fall für die gleiche Art von Zusammensetzung   oben beschriebenen Gründen. Irgendein   nicht-determinis Klasse, die ein   bis es würde nicht die Destruktoraufrufs   abgeschlossen wurde ohnehin von der GC.

     

(2) Kopierkonstruktoren - Der einzige Ort   wo es wäre wirklich schön, ist in   Stapel reserviert Einheimischen. Sie würden sein   das Verfahren scoped und alle wären   groß. um Leider zu bekommen   dies wirklich funktioniert, müssen Sie auch   fügen Sie Kopierkonstruktoren und rufen   jedes Mal wird eine Instanz kopiert.   Dies ist einer der hässlichsten und die meisten   komplexe Dinge über C ++. Du endest   immer Code der ganze Ausführung   Ort, wo man es nicht erwartet haben. Es   verursacht Bündel von Sprachproblemen.   Einige Sprachdesigner haben sich entschieden,   bleiben weg von diesem.

     

Lassen Sie uns sagen, dass wir geschaffen structs mit   Destruktoren fügte aber hinzu, eine Reihe von   Einschränkungen, ihr Verhalten zu machen   sinnvoll angesichts der Probleme   über. Die Einschränkungen wären   so etwas wie:

     

(1) Sie können sich nur als lokal erklären   Variablen.

     

(2) Sie können sie nur passieren   by-ref

     

(3) Sie können sie nicht zuordnen, können Sie   können nur auf Felder und Call   Methoden auf sie.

     

(4) Sie können nicht boxen   Sie.

     

(5) Probleme mit ihnen durch   Reflection (späte Bindung), weil das   in der Regel beinhaltet Boxen.

     

vielleicht mehr,   aber das ist ein guter Anfang.

     

Welcher Nutzen wären diese Dinge? Würde   Sie erstellen tatsächlich eine Datei oder ein   Datenbankverbindung Klasse, die kann   NUR als lokale Variable verwendet werden? ich   glaube nicht, dass jemand wirklich tun würde.   Was würden Sie tun, ist stattdessen ein erstellen   Universalverbindungstor und dann   schafft eine automatische destructed Wrapper für   Verwendung als scoped lokale Variable. Das   Anrufer würde dann holen, was sie   verwenden wollte. Hinweis der Anrufer gemacht ein   Entscheidung und es ist nicht ganz   im Objekt selbst verkapselt.   Vorausgesetzt, dass Sie etwas verwenden könnte   wie kommen die Vorschläge in einem nach oben   Einige Abschnitte.

Der Ersatz für RAII in .NET ist die Verwendung-Muster, die fast so gut funktionieren, wenn Sie sich daran gewöhnen.

Die nächst Sie, dass bekommen, ist der sehr begrenzte stackalloc Operator.

Es gibt einige ähnliche Themen, wenn Sie nach ihnen suchen, aber im Grunde, was es läuft darauf hinaus, dass, wenn Sie auf .NET Raii wollen einfach eine IDisposable Typ implementieren und verwenden Sie die „using“ Anweisung determinis Entsorgung zu erhalten. Auf diese Weise viele der gleichen ideoms kann in nur einer etwas wordy Art und Weise implementiert und verwendet werden.

IMHO, die großen Dinge, die VB.net und C # benötigen, sind:

  1. a „mit“ Deklaration für Felder, die die Compiler Code verursachen würden erzeugen alle Felder so getaggt zu entsorgen. Das Standardverhalten sollte für den Compiler zu einer Klasse IDisposable zu machen implementieren, wenn es nicht den Fall ist, oder Entsorgung Logik einfügen vor dem Start der Hauptentsorgungs Routine für eine beliebige Anzahl von gemeinsamen IDisposal Implementierung Mustern oder auch ein Attribut verwenden, um festzulegen, dass die Entsorgung Sachen sollten in einer Routine mit einem bestimmten Namen gehen.
  2. ein Mittel, determinis Entsorgung von Objekten, deren Erbauer und / oder Feld initializers wirft eine Ausnahme, entweder durch eine Standardverhalten (Aufruf der Standard-Entsorgungsmethode) oder ein benutzerdefiniertes Verhalten (ein Verfahren mit einem bestimmten Namen zu nennen) .
  3. Für vb.net, ein automatisch generierter Methode, um alle Felder Withevent auf Null zu bringen.

Alle diese können in vb.net kludged ziemlich gut sein, und etwas weniger gut in C #, aber erstklassige Unterstützung für sie würde beiden Sprachen verbessern.

Sie können in .NET- und Java eine Form von RAII tun finalisieren mit () Methoden. Eine Finalisierung () Überlastung aufgerufen wird, bevor die Klasse von der GC wird gereinigt und kann so verwendet werden, um alle Ressourcen zu bereinigen, die absolut nicht von der Klasse (Mutexe, Steckdosen, Datei-Handles, usw.) gehalten werden. Es ist immer noch nicht, obwohl deterministisch.

Mit .NET können Sie einige dieses deterministisch mit dem IDisposable-Schnittstelle zu tun und der Verwendung von Keyword, aber dies tut Einschränkungen hat (zu verwenden, wenn erforderlich für deterministisches Verhalten verwendet Konstrukt, noch keine deterministische Speicherfreigabe, nicht automatisch in Klassen verwendet, usw. ).

Und ja, ich fühle mich gibt es einen Platz für RAII Ideen in .NET und andere verwaltete Sprachen eingeführt werden, obwohl der genaue Mechanismus endlos diskutiert werden könnte. Die einzige andere Alternative, die ich sehen könnte, wäre eine GC einzuführen, die willkürliche Ressourcenbereinigung (nicht nur Speicher) umgehen konnte, aber dann Probleme, die Sie haben, wenn die Ressourcen absolut deterministisch gelöst werden müssen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top