2009-12-08 14 views
6

Estoy tratando de diseñar una clase que pueda actualizar una referencia a un objeto (fuera de la clase) en la destrucción.Almacenando una referencia en C#

Así que esencialmente usted crea una instancia de este objeto y le pasa un tipo de referencia (de cualquier manera, constructor, etc.) y luego en la destrucción del objeto la referencia original ha cambiado a una referencia creada por el objeto.

Si paso una referencia por referencia (digamos en construcción) no puedo encontrar la forma de almacenar esta referencia (como referencia) para que el destructor la actualice? Por ejemplo (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 
    } 
} 

La clave aquí es que no estoy tratando de mutar el objeto original 'externo' de esta clase que estoy tratando de 're-apuntar', o inicializar que si se quiere .

+0

Si está destruyendo su objeto, ¿por qué 'volver a marcar' un campo interno que también se destruirá? – Oded

+0

im no tratando de volver a marcar el campo interno, ese es el punto. Estoy tratando de volver a señalar lo que señala ... si eso tiene sentido. –

+2

Nunca es legal crear un campo (o cualquier otro almacenamiento basado en heap, como un elemento de matriz) que almacena una referencia a una variable. El motivo es que la referencia podría ser una referencia a una variable local en la pila cuya vida útil es más corta que el almacenamiento que contiene la referencia, por lo que la ref no es válida. Podemos (1) hacer refs inseguros y quebradizos, como C++, o (2) restringir el almacenamiento de refs y mantener a los ref siempre seguros, o (3) nunca almacenar cosas en la pila. Elegimos (2). –

Respuesta

7

No puedes hacer esto, básicamente. ref solo es aplicable dentro del método mismo, efectivamente.

No está del todo claro para qué quiere usar esto, ¿podría darnos más información para que podamos sugerir diseños alternativos? Todo lo que dependa de un finalizador es preocupante para comenzar, para ser honesto ...

+0

¡Precisamente de lo que tenía miedo! Es una implementación de un generador de perfiles que una vez vi en C++ ... básicamente creas una instancia de Profiler (pasando una variable que se llena con (en este caso) un objeto de intervalo de tiempo ya que el Profiler queda fuera del alcance. Fue muy elegante pero obviamente se basó en la asignación del puntero ... –

+1

Los finalizadores no se ejecutan cuando las variables caen fuera del alcance, así que esa es otra razón por la que no funcionaría ... –

1

Tenga en cuenta que usar un Finalizer como este no es lo mismo que un destructor en C++.

Cuando la última referencia muere (quizás se sale del alcance) el objeto va a la cola del Finalizador. El GC determina cuándo llamar al Finalizador y puede pasar mucho tiempo después de que fallezca la última referencia.

4

Esto no funcionará porque el aspecto ref del parámetro constructor solo se aplica dentro del constructor.

Lo que haría es darle al constructor un delegado que se pueda usar para actualizar el objeto en cuestión. Además, debe usar IDisposable para esto (junto con un bloque using) en lugar de un finalizador; los finalizadores no deben tocar objetos administrados (están diseñados para liberar objetos no administrados).

class Updater : IDisposable 
{ 
    Action<object> setter; 

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

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

Este es realmente el enfoque que toma el ejemplo que estoy adaptando .. . Esta es una opción, pero quería desacoplarlo un poco. –

Cuestiones relacionadas