2009-12-08 18 views
6

Ich versuche, eine Klasse zu entwerfen, die einen Verweis auf ein Objekt (außerhalb der Klasse) bei der Zerstörung aktualisieren kann.Speichern einer Referenz in C#

Also im Wesentlichen erstellen Sie eine Instanz dieses Objekts und übergeben Sie einen Referenztyp (in welcher Weise, Konstruktor usw.) und dann auf die Zerstörung des Objekts die ursprüngliche Referenz hat sich zu einer Referenz durch das Objekt erstellt.

Wenn ich eine Referenz durch Verweis (sagen wir in Konstruktion) übergebe, kann ich keine Möglichkeit finden, diese Referenz (als Referenz) für den Destruktor zu speichern, um sie zu aktualisieren? Zum Beispiel (pseudo):

class Updater 
{ 
    object privateReference; 
    public Updater(ref object externalReference) 
    { 
     privateReference = externalReference; //is privateReference now a new reference to the original object? 
    } 

    ~Updater() 
    { 
     privateReference = new object(); //therefore this isn't 'repointing' the externalReference 
    } 
} 

Der Schlüssel hier ist, ich bin nicht das Original ‚externe‘ Objekt von dieser Klasse ich versuche zu mutieren versuchen ‚repoint‘ es oder es initialisieren, wenn Sie werden .

+0

Wenn Sie Ihr Objekt zerstören, warum "repoint" ein internes Feld, das auch zerstört wird? – Oded

+0

Ich versuche nicht, das interne Feld zu repozieren, das ist der Punkt. Ich versuche das Ding, auf das es hinweist, neu zu definieren ... wenn das Sinn macht. –

+2

Es ist niemals legal, ein Feld (oder irgendeinen anderen Heap-basierten Speicher, wie ein Array-Element) zu erstellen, der einen Verweis auf eine Variable speichert. Der Grund dafür ist, dass der Ref ein Verweis auf eine lokale Variable auf dem Stack sein könnte, deren Lebensdauer kürzer ist als der Speicher, der den Ref hält, wodurch der Ref ungültig wird. Wir können (1) Refs unsicher und spröde machen, wie C++, oder (2) die Speicherung von Refs einschränken und Refs immer sicher aufbewahren, oder (3) niemals Dinge auf dem Stack speichern. Wir haben (2) gewählt. –

Antwort

7

Sie können dies grundsätzlich nicht tun. ref ist nur innerhalb der Methode selbst effektiv anwendbar.

Es ist überhaupt nicht klar, wofür Sie das verwenden möchten - könnten Sie uns mehr Informationen geben, damit wir alternative Designs vorschlagen können? Alles, was auf einen Finalizer angewiesen ist, ist beunruhigend, um ehrlich zu sein ...

+0

Genau das, wovor ich Angst hatte! Es ist eine Implementierung eines Profilers, den ich einmal in C++ gesehen habe ... im Grunde erstellen Sie eine Profiler-Instanz (übergeben eine Variable, die mit (in diesem Fall) einem Zeitspannenobjekt gefüllt wird, da der Profiler außerhalb des Gültigkeitsbereichs liegt offensichtlich auf Pointer Assignment ... –

+1

Finalizer werden nicht ausgeführt, wenn Variablen fallen außerhalb des Geltungsbereichs, also das ist ein weiterer Grund, warum es nicht funktionieren würde ... –

1

Beachten Sie, dass die Verwendung eines Finalizer wie folgt nicht identisch ist mit einem Destruktor in C++.

Wenn die letzte Referenz stirbt (vielleicht geht sie außerhalb des Bereichs), geht das Objekt in die Finalizer-Warteschlange. Der GC bestimmt, wann der Finalizer aufgerufen werden soll, und es kann lange dauern, bis die letzte Referenz stirbt.

4

Dies funktioniert nicht, da der ref Aspekt des Konstruktor-Parameters nur innerhalb des Konstruktors gilt.

Was ich tun würde, ist, dem Konstruktor einen Stellvertreter zu geben, der verwendet werden kann, um das Ding in Frage zu aktualisieren. Außerdem sollten Sie dafür IDisposable (in Verbindung mit einem using Block) anstelle eines Finalizers verwenden; Finalizer sollten verwaltete Objekte nicht berühren (sie sind entworfen, um nicht verwaltete Objekte zu befreien).

class Updater : IDisposable 
{ 
    Action<object> setter; 

    public Updater(Action<object> setter) 
    { 
     this.setter = setter; 
    } 

    public Dispose() 
    { 
     setter(new object()); 
    } 
} 
+0

Dies ist eigentlich der Ansatz, den das Beispiel, das ich anpasse, dauert .. Dies ist eine Option, aber ich wollte es leicht entkoppeln. –