Design-Dilemma: Wer sollte mit Einwegparametern umgehen?

8

Wenn meine Klasse eine verfügbare Ressource im Konstruktor verwendet ( DbConnection , wenn es darauf ankommt), sollte ich IDisposable in meiner Klasse implementieren und DbConnection object abschaffen oder den Benutzer die Entsorgung von DbConnection übernehmen lassen?

Gegenwärtig implementiere ich IDisposable in meiner Klasse, aber jetzt sehe ich einige mögliche negative Auswirkungen: clutters class design, doppelte Beseitigung von DbConnection bei falscher Verwendung. Aber es gibt auch positive: die einfachere Verwendung ist die wichtigste (vor allem, wenn Sie mehrere Einwegparameter verwenden).

Im "wilden" sehe ich beide Ansätze, also kann ich mich nicht entscheiden ..

Aktualisierung: Danke allen für die Antworten, was in der Tat gezeigt hat, dass es manchmal keine einfache Wahl ist. Und es ist schwer, die richtige Antwort zu wählen. Ich habe mich jedoch dazu entschlossen, in Zukunft dem einfachsten zu folgen. Die endgültige Entscheidung lautet also: IDisposable nicht implementieren.

    
Petr Abdulin 24.06.2011, 12:18
quelle

4 Antworten

4

Es sollte von demjenigen entsorgt werden, der es erstellt hat - dem gleichen Umfang wie seine Erstellung. Sie erstellen ein Objekt, Sie sind dafür verantwortlich, es zu entsorgen. Einfach so.

    
Kieren Johnstone 24.06.2011, 12:33
quelle
4

Die Verwendung einer wegwerfbaren Ressource in einem Konstruktor ist nicht optimal und kann zu Fremdheit führen. Sie sollten stattdessen einen DbConnectionFactory in den Konstruktor einfügen, der in der Lage ist, bei Bedarf Verbindungen zu erstellen, die Sie verwenden und intern in Ihren Methoden ablegen können.

Wenn dieses Muster aus irgendeinem Grund für Ihr Szenario unlogisch wäre. Die nächstbeste Option wäre, die Verwendung der Einweg-Ressource immer noch aus dem Konstruktor zu entfernen und eine Methode einen neuen Typ zurückgeben zu lassen, der wegwerfbar ist und Ihren Zweck erfüllt.

Dies entspricht Ihrer Servicetypklasse, die einen Datenreader zurückgibt, der aus einer Methode entfernt werden muss. (Theoretisch könnte es ein echter Datenleser sein)

    
Chris Marisic 24.06.2011 12:30
quelle
1

Ich würde entweder :

  1. Implementieren Sie nicht IDisposable ; Der aufrufende Code ist dafür verantwortlich, das übergebene Objekt zu entsorgen und sicherzustellen, dass es mindestens so lange wie das neue Objekt lebt.

Oder:

  1. Implementieren IDisposable ; der aufrufende Code gibt das Eigentum an dem übergebenen Objekt auf und sollte es als bereits entsorgt behandeln.

Und dokumentieren eindeutig, welche Wahl ich getroffen habe. Der Versuch, das Wegwerfobjekt an mehreren Orten in Besitz zu nehmen, ist zu wahrscheinlich, dass es eines Tages schief geht, IMHO.

Option 1 ist für das Szenario, in dem Sie beabsichtigen, das wegwerfbare Objekt in mehrere neue Objekte zu übergeben, die den Zugriff darauf teilen (eine Datenbankverbindung hört sich an, als wäre sie das). Option 2 ist, wenn das, was Sie tun, eher das Wegwerfen des wegwerfbaren Objekts in einem anderen Objekt mit mehr (oder abstrakterer) Funktionalität ist, besonders wenn Sie es zurückgeben und so seine Lebensdauer nicht kontrollieren.

    
Ben 24.06.2011 12:56
quelle
0

Es gibt Situationen, in denen ein Objekt eine wegwerfbare Ressource verwendet, deren Nutzungsdauer die Lebensdauer des neuen Objekts übersteigt, das sie verwendet hat. Es wird andere Situationen geben, in denen man erwartet, ein Objekt an eine Entität zu übergeben, die nichts über Einwegartikel weiß. Einige Arten von Objekten können in beiden Szenarien verwendet werden.

Betrachten Sie einen hypothetischen IDisposable SoundPlayer-Typ, der ein IDisposable SoundSource-Objekt abspielt und sich dann selbst erledigt, wenn es fertig ist. Es ist leicht sich Situationen vorzustellen, in denen man eine SoundSource einmal laden, mehrere Male abspielen und dann manuell wieder entfernen könnte. Es ist auch leicht, sich Situationen vorzustellen, in denen man ein SoundSource-Objekt laden und dann den Player "feuern und vergessen" würde. Der Ersteller der SoundSource kann es nicht entsorgen, bis der Player fertig ist, aber danach keinen Nutzen mehr haben wird. Daher ist es für den SoundPlayer die beste Vorgehensweise, darüber zu verfügen.

Ich würde vorschlagen, dass, wenn beide Szenarien zumindest plausibel sind, Sie entweder eine Factory-Methode angeben sollten, die den Besitz des IDisposable überträgt, oder eine Factory-Methode mit einem Parameter, der angibt, ob Eigentum sollte übertragen werden. Beachten Sie, dass das Übergeben von IDisposables an Konstruktoren für Klassen, die sie konsumieren und disponieren sollen, gefährlich ist, da Microsoft try / catch-Blöcke um Konstruktoren, die von Feldinitialisierern aufgerufen werden, nicht erlaubt und es schwierig ist, sicherzustellen, dass Dinge beim Konstruieren verworfen werden. Mit einem Factory-Methodenaufruf macht der Konstruktor die Fehlersuche viel einfacher (obwohl es immer noch ein Schmerz ist - besonders in C #).

Bearbeiten - Nachtrag Eine andere Situation, die manchmal nützlich ist, besteht darin, dass ein Objekt entweder ein Disposed-Ereignis veröffentlicht oder einen Delegaten in seinem Konstruktor akzeptiert, um ausgeführt zu werden, wenn das übergebene Objekt nicht mehr benötigt wird. Ich bevorzuge den expliziten Delegierten für das Ereignis, da die Verwendung eines Ereignisses bedeuten würde, dass der Ereignisteilnehmer (die Person, die das Objekt erstellt, das vorübergehend die verfügbare Ressource hält) eine Abmeldepflicht hat, was zusätzliche Komplikationen mit sich bringt, insbesondere wenn das Objekt möglicherweise ist an ein anderes Objekt übergeben. Da der Aufrufer bei weitem die üblichste Sache sein möchte, wenn der Empfänger des Objekts nicht mehr benötigt, ist, dass das Objekt einfach gelöscht wird, der einfachste Fall besteht einfach darin, eine Option für den Objektempfänger zu haben, um die Entsorgung selbst zu handhaben .

    
supercat 24.06.2011 23:13
quelle

Tags und Links