Warum gibt es in.NET keine RAII?



struct destructor (5)

Da ich in erster Linie ein C ++ - Entwickler bin, hat mich das Fehlen von RAII (Resource Acquisition Is Initialization) in Java und .NET immer gestört. Die Tatsache, dass die Aufgabe der Bereinigung vom Klassenschreiber zum Konsumenten (mittels try finally oder .NET using Konstrukt ) verschoben wird, scheint deutlich unterlegen zu sein.

Ich sehe, warum in Java RAII nicht unterstützt wird, da sich alle Objekte auf dem Heap befinden und der Garbage Collector von Natur aus keine deterministische Destruktion unterstützt, aber in .NET mit der Einführung von struct ( struct ) haben wir die (anscheinend ) perfekter Kandidat für RAII. Ein Werttyp, der auf dem Stapel erstellt wird, hat einen klar definierten Bereich, und C ++ - Destruktorsemantik kann verwendet werden. Die CLR lässt jedoch nicht zu, dass ein Werttyp einen Destruktor hat.

Meine zufälligen Suchen fanden ein Argument, dass, wenn ein Werttyp eingerahmt ist, er in den Zuständigkeitsbereich des Müllsammlers fällt und daher seine Zerstörung nicht deterministisch wird. Ich finde, dass dieses Argument nicht stark genug ist, die Vorteile von RAII sind groß genug, um zu sagen, dass ein Werttyp mit einem Destruktor nicht eingerahmt (oder als Klassenmitglied verwendet) werden kann.

Um es kurz zu machen: Meine Frage lautet : Gibt es noch andere Gründe, warum Werttypen nicht verwendet werden können, um RAII in .NET einzuführen? (Oder glauben Sie, dass meine Argumentation über die offensichtlichen Vorteile von RAII fehlerhaft ist?)

Edit: Ich muss die Frage nicht klar formuliert haben, da die ersten vier Antworten den Punkt verfehlt haben. Ich weiß über Finalize und seine nicht-deterministischen Eigenschaften, ich weiß über das using Konstrukt Bescheid using und ich denke, diese beiden Optionen sind schlechter als RAII. using ist eine weitere Sache, an die sich der Konsument einer Klasse erinnern muss (wie viele Leute haben vergessen, einen StreamReader in einen using zu setzen?). Meine Frage ist eine philosophische über das Sprachdesign, warum ist es so wie es ist und kann es verbessert werden?

Zum Beispiel kann ich mit einem generischen deterministisch zerstörbaren lock Schlüssel zum using und lock überflüssig machen (erreichbar durch Bibliotheksklassen):

    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();
        }
    }

Ich kann nicht anders, als mit einem passenden Zitat zu enden, das ich einst gesehen habe, aber gegenwärtig seinen Ursprung nicht finden kann.

Du kannst meine deterministische Zerstörung hinnehmen, wenn meine kalte, tote Hand außer Reichweite gerät. - Anon

https://ffff65535.com


Am nächsten kommt man dem sehr eingeschränkten Stackalloc-Operator.


Ausgezeichnete Frage und eine, die mich sehr gestört hat. Es scheint, dass die Vorteile von RAII sehr unterschiedlich wahrgenommen werden. Nach meiner Erfahrung mit .NET ist das Fehlen einer deterministischen (oder zumindest zuverlässigen) Ressourcensammlung einer der Hauptnachteile. Tatsächlich hat .NET mich mehrfach gezwungen, ganze Architekturen zu verwenden, um mit nicht verwalteten Ressourcen umzugehen, die ein explizites Sammeln erfordern könnten (aber möglicherweise nicht). Das ist natürlich ein großer Nachteil, weil es die gesamte Architektur erschwert und die Aufmerksamkeit des Kunden von den zentralen Aspekten ablenkt.


Ein besserer Titel wäre "Warum gibt es keine RAII in C # / VB". C ++ / CLI (Die Evolution der Abtreibung, die Managed C ++ war) hat RAII im genau gleichen Sinne wie C ++. Es ist alles nur Syntax Zucker für das gleiche Finalisierungsmuster, das der Rest der CLI-Sprachen verwendet (Destruktoren in verwalteten Objekten für C ++ / CLI sind effektiv Finalisten), aber es ist da.

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


Es gibt einige ähnliche Threads, wenn Sie nach ihnen suchen, aber grundlegend, worauf es hinausläuft ist, dass, wenn Sie RAII auf .NET wollen, einfach einen IDisposable-Typ implementieren und die "using" -Anweisung verwenden, um deterministische Entsorgung zu erhalten. Auf diese Weise können viele der gleichen Ideome nur etwas wortwörtlicher umgesetzt und verwendet werden.


Sie können eine Form von RAII in .net und Java mit finalize () Methoden machen. Eine finalize () - Überladung wird aufgerufen, bevor die Klasse vom GC bereinigt wird, und kann daher zum Bereinigen von Ressourcen verwendet werden, die von der Klasse nicht unbedingt gehalten werden sollten (Mutexe, Sockets, Dateihandles usw.). Es ist jedoch immer noch nicht deterministisch.

Mit .NET können Sie einiges deterministisch mit der IDisposable-Schnittstelle und dem using-Schlüsselwort tun, aber dies hat Einschränkungen (Konstruieren, wenn es für deterministisches Verhalten benötigt wird, noch keine deterministische Speicherfreigabe, nicht automatisch in Klassen verwendet, usw.).

Und ja, ich glaube, dass es einen Platz für RAII-Ideen gibt, die in .NET und anderen verwalteten Sprachen eingeführt werden, obwohl der genaue Mechanismus endlos diskutiert werden könnte. Die einzige andere Alternative, die ich sehen könnte, wäre die Einführung eines GC, der beliebige Ressourcenbereinigungen (nicht nur Speicher) verarbeiten könnte, aber dann gibt es Probleme, wenn diese Ressourcen unbedingt deterministisch freigegeben werden müssen.





value-type