2010-01-15 9 views
23

Necesito saber cómo se comprueba si se cambia un objeto. Básicamente, necesito algo así como una propiedad que se denomina TrackChanges, cuando lo configuro como verdadero una vez y si cualquier dato dentro de este objeto se "cambia", un método en el mismo objeto (IsObjectChanged) puede devolver verdadero.¿Cuál es la mejor práctica para verificar si se cambia un objeto?

¿Alguna vez necesitó algo así y cómo lo resolvió? No quiero inventar la rueda si ya hay una mejor práctica para tal escenario?

Estaba pensando en clonar el objeto antes de llamar a TrackChange = true, en su setter. Y cuando llamo a IsObjectChanged() Al usar reflection compararé todos los valores de campo público del mismo con la copia clonada. No estoy seguro si es una buena manera.

¿Algún consejo?

gracias, Burak Ozdogan

+0

posible duplicado de [¿Cuál es la mejor manera de saber si se modifica un objeto?] (Http://stackoverflow.com/questions/34809/what- is-the-best-way-to-tell-if-an-object-is-modified) – mathieu

Respuesta

16

Cuando necesito realizar un seguimiento de los cambios en las propiedades de los objetos de mi para las pruebas engancho un controlador de eventos en los objetos de eventos PropertyChanged. ¿Eso te ayudará? Entonces sus pruebas pueden hacer cualquier acción que quieran en base al cambio. Normalmente cuento el número de cambios y agrego los cambios a diccionarios, etc.

Para lograr esto, su clase debe implementar la interfaz INotifyPropertyChanged. Entonces cualquiera puede conectar y escuchar propiedades modificadas:

public class MyClass : INotifyPropertyChanged { ... } 

[TestFixture] 
public class MyTestClass 
{ 
    private readonly Dictionary<string, int> _propertiesChanged = new Dictionary<string, int>(); 
    private int _eventCounter; 

    [Test] 
    public void SomeTest() 
    { 
     // First attach to the object 
     var myObj = new MyClass(); 
     myObj.PropertyChanged += SomeCustomEventHandler; 
     myObj.DoSomething(); 
     // And here you can check whether the object updated properties - and which - 
     // dependent on what you do in SomeCustomEventHandler. 

     // E.g. that there are 2 changes - properties Id and Name changed once each: 
     Assert.AreEqual(2, _eventCounter); 
     Assert.AreEqual(1, _propertiesChanged["Id"]); 
     Assert.AreEqual(1, _propertiesChanged["Name"]); 
    } 

    // In this example - counting total number of changes - and count pr property. 
    // Do whatever suits you. 
    private void SomeCustomEventHandler(object sender, System.ComponentModel.PropertyChangedEventArgs e) 
    { 
     var property = e.PropertyName; 
     if (_propertiesChanged.ContainsKey(property)) 
      _propertiesChanged[property]++; 
     else 
      _propertiesChanged[property] = 1; 

     _eventCounter++; 
    } 
} 
+0

¡Agradable! Preguntas de la oficina: 1) ¿Qué se considera como "cambio"? En msdn dice que se lanza cuando se llama al setter. Así que aún necesito verificar si es diferente al valor anterior, ¿verdad? 2) ¿Qué pasa si una propiedad de este objeto es una referencia a otro tipo de objeto, y si la propiedad de ese objeto se cambia, creo que el caso se vuelve mucho más complicado. algo como: myPerson.Address.Ctiy = "aDifferentCityName" – pencilCake

+0

Un cambio es un evento PropertyChanged. Implementando la interfaz INotifyPropertyChanged necesita activar los eventos usted mismo. Como usted mismo lo controla, básicamente puede elegir si desea que un cambio al mismo valor se considere un cambio. Yo no. – stiank81

+0

Si MyObject tiene una propiedad que refiere a otro objeto y desea eventos PropetyChanged cuando este también se cambia, MyObject necesita enganchar un evento PropertyChanged en su objeto referenciado y desencadenar un evento cambiado para pasarlo. Seguro que se vuelve más complicado. Puede ser difícil al principio, pero en realidad no es tan complicado cuando lo entiendes. ¡Buena suerte! – stiank81

3

Burak,

Es posible echar un vistazo a Entity Framework u otro marco de Microsoft. Puede ver eventos como PropertyChanging o PropertyChanged.

Eche un vistazo al código generado.

Es posible tomar un vistazo al código NHibernate también, pero ya que el código base es tan grande, mejor mirar a los generadores de Microsoft ORM ..

0

En lugar de crear una propiedad que debe ser la creación de un evento y llámalo algo así como OnChanged.

1

¿Por qué no crea una lista y coloca su primer objeto? Entonces puede compararlo con el objeto actual mediante una simple comparación.

Como arriba puedes usar INotifyPropertyChanged para ver qué propiedades han cambiado en tu objeto.

+1

Una comparación simple requeriría la creación de una copia (profunda) de su objeto. Eso es costoso tanto en memoria como en tiempo. –

4

Hay dos partes en esto. Los eventos para notificación de cambio son de una sola pieza, pero mantener la historia es otra pieza importante. Entity Framework también lo hace (al igual que LINQ to SQL), y lo he implementado en mi propio código también. Como mínimo, conserve una bandera para que un miembro diga que ha cambiado. Dependiendo de sus requisitos, puede mantener el valor original también. Esto generalmente se convierte en la tarea de un objeto separado. Entity Framework mantiene su seguimiento de cambios en un objeto separado (EntityState, si no recuerdo mal).

En mi propio código, desarrollé una clase "DataMember" que no solo contenía los valores, sino que también guardaba la marca de cambio, el estado nulo y varias otras cosas útiles.Estos DataMembers eran miembros privados en una clase Entity, y la Entidad proporcionaba propiedades que exponían los datos como tipos de datos simples. Los métodos get y set de la propiedad interactuaron con el DataMember para "hacer lo correcto", pero el DataMember sí modificó el seguimiento. Mi clase Entity heredó de una clase "EntityBase" que proporcionó métodos para verificar el cambio a nivel de entidad, aceptar cambios (restablecer indicadores de cambio), etc. Agregar lo siguiente a la notificación de cambio, pero tener una clase DataMember para cada individuo elementos de datos, y una EntityBase para poseer el controlador de eventos de notificación de cambio, simplificará mucho esto.

editar para agregar:

Ahora que estoy en el trabajo, puedo añadir algunos ejemplos de código. Aquí está la definición de interfaz para mi clase DataMember:

public interface IDataMember<T> : IDataMember 
{ 
    T Value { get; set; } 

    T Get(); 

    void Set(T value); 
} 

public interface IDataMember 
{ 
    string FieldName { get; set; } 
    string OracleName { get; set; } 
    Type MemberType { get; } 
    bool HasValue { get; set; } 
    bool Changed { get; set; } 
    bool NotNull { get; set; } 
    bool PrimaryKey { get; set; } 
    bool AutoIdentity { get; set; } 
    EntityBase Entity { get; set;} 

    object GetObjectValue(); 

    void SetNull(); 
} 

aquí es una característica típica de una clase de entidad:

private DataMember<bool> m_Monday; 

public bool? Monday 
{ 
    get 
    { 
     if (m_Monday.HasValue) 
      return m_Monday.Get(); 
     else 
      return null; 
    } 
    set 
    { 
     if (value.HasValue) 
      m_Monday.Set(value.Value); 
     else 
      m_Monday.SetNull(); 
    } 
} 

Tenga en cuenta que el DataMember puede apoyar propiedades como anulable, o no.

código de constructor para añadir un DataMember:

m_Monday = new DataMember<bool>("Monday"); 
    Members.Add(m_Monday); 
Cuestiones relacionadas