2010-01-15 8 views
23

Ho bisogno di sapere come si controlla se un oggetto è cambiato. Fondamentalmente ho bisogno di qualcosa come una proprietà che si chiama TrackChanges, quando l'ho impostato true una volta e se qualsiasi dato all'interno di questo oggetto è "cambiato", un metodo sullo stesso oggetto (IsObjectChanged) può restituire true.Qual è la procedura migliore per verificare se un oggetto viene modificato?

Hai mai avuto bisogno di una cosa del genere e come l'hai risolta? Non voglio inventare la ruota se esiste già una best practice per tale scenario?

Stavo pensando di clonare l'oggetto prima di chiamare TrackChange = true, nel suo setter. E quando chiamo IsObjectChanged() utilizzando la reflection confronterò tutti i valori del campo pubblico con la copia clonata. Non sono sicuro che sia un buon modo.

Eventuali consigli?

grazie, Burak Ozdogan

+0

possibile duplicato di [Qual è il modo migliore per dire se un oggetto viene modificato?] (Http://stackoverflow.com/questions/34809/what- is-the-best-way-to-tell-if-an-object-is-modified) – mathieu

risposta

16

Quando ho bisogno di tenere traccia delle modifiche alle proprietà sui miei oggetti per i test collego un gestore di eventi sugli oggetti evento PropertyChanged. Questo ti aiuterà? Quindi i tuoi test possono fare qualunque azione essi vogliano in base al cambiamento. Normalmente conto il numero di modifiche e aggiungo le modifiche ai dizionari, ecc.

Per raggiungere questo obiettivo, la classe deve implementare l'interfaccia INotifyPropertyChanged. Poi chiunque può collegare e ascoltare le proprietà modificate:

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

Bello! Domande Bur: 1) Cosa si intende per "modifica?" In msdn dice che viene lanciato quando viene chiamato il setter. Quindi ho ancora bisogno di controllare se è diverso dal valore precedente, giusto? 2) Cosa succede se una proprietà di questo oggetto è un riferimento a un altro tipo di oggetto e se la proprietà dell'oggetto viene modificata, penso che il caso diventi molto più complicato. qualcosa come: myPerson.Address.Ctiy = "aDifferentCityName" – pencilCake

+0

Una modifica è un evento PropertyChanged. Implementando l'interfaccia INotifyPropertyChanged è necessario attivare autonomamente gli eventi. Mentre controlli questo te stesso puoi sostanzialmente scegliere se vuoi che una modifica dello stesso valore sia considerata una modifica. Io non. – stiank81

+0

Se MyObject ha una proprietà che fa riferimento a un altro oggetto e si desidera che gli eventi PropetyChanged vengano modificati anche in questo caso, MyObject deve agganciare un evento PropertyChanged sul suo oggetto di riferimento e attivare un evento modificato per passarlo. Di certo diventa più complicato - Potrebbe essere difficile all'inizio, ma non è poi così complicato quando lo capisci. In bocca al lupo! – stiank81

3

Burak,

Si potrebbe dare un'occhiata al Entity Framework o l'altro quadro di Microsoft. È possibile visualizzare eventi come PropertyChanging o PropertyChanged.

Dai un'occhiata al codice generato.

Si potrebbe dare un'occhiata al codice NHibernate pure, ma dal momento che il codice di base è così enorme, meglio guardare i generatori Microsoft ORM ..

0

Invece di creare una proprietà che dovrebbe essere la creazione di un evento e chiamalo qualcosa come OnChanged.

1

Perché non si crea una lista e si inserisce il primo oggetto, quindi è possibile confrontarlo con l'oggetto corrente utilizzando un semplice confronto.

Come sopra, è possibile utilizzare INotifyPropertyChanged per vedere quali proprietà sono state modificate nell'oggetto.

+1

Un confronto semplice richiede la creazione di una copia (profonda) dell'oggetto. Questo è costoso sia nella memoria che nel tempo. –

2

Implementare e utilizzare l'interfaccia INotifyPropertyChanged. Un modo interessante per farlo senza stringhe letterali è here.

4

Ci sono due parti a questo. Gli eventi per la notifica del cambiamento sono un pezzo, ma il mantenimento della storia è un altro tassello importante. Entity Framework fa anche questo (come fa LINQ a SQL) e l'ho implementato anche nel mio codice. Come minimo, si mantiene una bandiera per un membro per dire che è cambiata. A seconda delle tue esigenze, puoi mantenere anche il valore originale. Questo di solito diventa il compito di un oggetto separato. Entity Framework mantiene il rilevamento delle modifiche in un oggetto separato (EntityState, se non ricordo male).

Nel mio codice, ho sviluppato una classe "DataMember" che non solo conteneva i valori, ma manteneva anche il flag di modifica, lo stato null e varie altre cose utili.Questi DataMembers erano membri privati ​​in una classe Entity e le entità fornivano proprietà che esponevano i dati come semplici tipi di dati. La proprietà ottiene e imposta i metodi interagiti con DataMember per "fare la cosa giusta", ma DataMember ha modificato il tracciamento. La mia classe Entity è stata ereditata da una classe "EntityBase" che ha fornito metodi per verificare la modifica a livello di entità, accettare modifiche (reimpostare i flag di modifica), ecc. Aggiungere una notifica di modifica sarà la prossima cosa che faccio, ma avere una classe DataMember per singoli elementi di dati, e un EntityBase per possedere il gestore di eventi di notifica delle modifiche, semplificherà molto questo.

A cura di aggiungere:

Ora che sono al lavoro, posso aggiungere alcuni esempi di codice. Ecco la definizione di interfaccia per la mia classe 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(); 
} 

Ecco una proprietà tipica in una classe di entità:

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(); 
    } 
} 

Si noti che il DataMember in grado di supportare le proprietà come annullabile, oppure no.

codice del costruttore per aggiungere un DataMember:

m_Monday = new DataMember<bool>("Monday"); 
    Members.Add(m_Monday); 
Problemi correlati