2010-02-27 17 views
6

He estado leyendo "Expert C# 2008 Business Objects" de Rockford Lhotka, donde existe un portal de datos que resume muy bien de dónde provienen los datos. Cuando se usa DataPortal.Update (esto), que como se puede adivinar persiste 'esto' en la base de datos, se devuelve un objeto - el 'this' persistente con cualquier cambio que se le haga al DB, por ejemplo. una marca de tiempoC#: ¿Hay alguna forma de encontrar/actualizar fácilmente todas las referencias a un objeto?

Lhotka ha escrito con frecuencia y muy a la ligera, que debe asegurarse de actualizar todas las referencias al objeto antiguo al nuevo objeto devuelto. Tiene sentido, pero ¿hay alguna manera fácil de encontrar todas las referencias al objeto anterior y cambiarlas? Obviamente, el GC rastrea referencias, ¿es posible aprovechar eso?

Saludos

Respuesta

4

El GC no rastrea en realidad las referencias a los objetos. En su lugar, calcula qué objetos son accesibles a partir de objetos globales y de pila en el tiempo de ejecución, y ejecuta alguna variante del algoritmo de "llenado de inundación".

Específicamente para su problema, ¿por qué no simplemente tener un proxy con referencia al objeto "real"? De esta forma, debe actualizar en un solo lugar.

+0

Sí, podría usar un patrón similar al de un Flyweight. http://en.wikipedia.org/wiki/Flyweight_pattern – Josh

+1

+1. Como Vlad ha señalado, una manera fácil es introducir un nivel más de indirección. (@Josh: ¿Estás seguro de que * Flyweight * es la terminología adecuada aquí?) –

+0

@andras, en el ejemplo de GoF que usa los glifos de un editor de texto como un ejemplo, puede parecer extraño. Pero si lo que quiere decir Vlad es tener un objeto de datos "pesado" que contiene los datos y un montón de otros objetos de "enlace" que hacen referencia a esto, sí, creo que sería muy similar a la intención de un peso mosca. Aunque el ahorro de espacio no es la principal motivación aquí. – Josh

5

Hay profiling API's hacer esto, pero no para el consumo general. Una posible solución y otra que he usado es implementar en una clase base un mecanismo de seguimiento donde cada instancia del objeto agrega una WeakReference a sí misma a una colección estática.

Tengo esto compilado condicionalmente para compilaciones DEBUG pero probablemente no sea una buena idea confiar en esto en una compilación de lanzamiento.

// simplified example 
// do not use. performance would suck 
abstract class MyCommonBaseClass { 

    static readonly List<WeakReference> instances = new List<WeakReference>(); 

    protected MyCommonBaseClass() { 
     lock (instances) { 
      RemoveDeadOnes(); 
      instances.Add(new WeakReference(this)); 
     } 
    } 

} 
+0

+1: Buena técnica para el caso cuando controlas el objeto. – Vlad

+0

Guau gran idea, gracias. – jptsetung

0

No hay una manera simple de hacer esto directamente, sin embargo, Son of Strike tiene esta capacidad. Le permite profundizar en todas las referencias de objetos rastreados por el CLR, y observar qué objetos hacen referencia a un objeto específico, etc.

Aquí hay un buen tutorial for learning CLR debugging via SoS.

0

Si pasa referencias de objetos y esas referencias no se modifican, cualquier cambio realizado en el objeto en una capa de persistencia será instantáneamente visible para cualquier otro consumidor del objeto. Sin embargo, si su objeto está cruzando un límite de servicio, los ensamblajes en cada lado del objeto verán diferentes objetos que son solo copias de carbono. Además, si ha creado clones del objeto o ha creado tipos anónimos que incorporan propiedades del objeto original, será difícil rastrearlos y, por supuesto, para el GC estos son objetos nuevos que no están relacionados con el objeto. objeto original.

Si tiene algún tipo de clave o ID en el objeto, entonces es más fácil. La clave no tiene que ser una ID de base de datos, puede ser un GUID que se actualiza cuando se crea una instancia del objeto, y no se cambia durante todo el ciclo de vida del objeto (es decir, es una propiedad que tiene una getter pero no setter) - ya que es una propiedad que persistirá a través de los límites del servicio, por lo que su objeto seguirá siendo identificable. A continuación, puede usar LINQ o incluso bucles pasados ​​de moda (¡repulsivo!) Para iterar a través de cualquier colección que pueda contener una copia del objeto actualizado, y si se encuentra uno puede fusionar los cambios nuevamente.

Habiendo dicho esto, no creo que tengas demasiadas copias flotando. Si lo hace, los lugares donde están estas copias deben estar muy localizados. Asegurarse de que su objeto implemente INotifyPropertyChanged también ayudará a propagar las notificaciones de cambios si mantiene una lista en un lugar que luego se verá directa o indirectamente en otros puntos.

Cuestiones relacionadas