tags:

views:

66

answers:

6

I have an application that needs to determine whether a user has made a change to an object. So, when the object is first loaded, I create a deep copy (using serialization/deserialization) and save the copy to a separate field. The copy becomes myCurrentObject, and the original becomes myOriginalObject.

Now I need to test myCurrentObject for changes, which I plan to do by comparing it to myOriginalObject. All I need is a boolean result indicating whether any changes have been made. I have already determined that a simple hashcode comparison won't work. GetHashCode() generates different results for the two objects, even when there are no changes.

I am getting ready to write a method to do a property-by-property comparison, but before I do, I thought I would check to see if there is a simpler and more reusable way to test myCurrentObject to see if it has changed from myOriginalObject.

Any suggestions? Thanks for your help.

+2  A: 

What if an event is raised when a property is changed?

http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.propertychanged.aspx

Raj Kaimal
+5  A: 

Instead could you implement a OnPropertyChanged event on each of your properties then you could just see if the event was ever thrown. If you specifically implement INotifyPropertyChanged, you will get the added benefit that you can do WPF binding if you ever want to.

If that isn't possible, you could probably implement a solution with reflection that would traverse both objects looking for differences.

Jake Pearson
That will definitely do it. +1 from me.
David Veeneman
+1  A: 

You could add a dirty flag that indicates any field has changed. Set the dirty flag in the property set.

public bool IsDirty { get { return m_IsDirty; } }
public string Name {
    set
    {
        m_Name = value;
        m_IsDirty = true;
    }
}   
Paul Williams
A: 

I usually do these kind of test like this:

public string sodomizar(myObject object)
{
   return object.prop1.ToString() + object.prop2.ToString();
}

then test:

if(sodomizar(object1)==sodomizar(object2))
{
doStuff();
}
Luiscencio
+2  A: 
  1. You can override the GetHashCode method to reflect your needs.
  2. The hash code can only tell you that an object has definately changed, it cannot tell you that an object definately hasn't changed (because different objects can return the same hash code).
  3. Do investigate the Object.Equals method
M.A. Hanin
Helpful-- it's a +1 from me.
David Veeneman
A: 

I would consider using an abstract superclass containing two things:

  • a flag that declares whether 'track changes' is on or not (default to false)
  • a Dictionary instance that contains keyed value history

... then call Base.TrackChange(string, object) in each property accessor upon which you are interested in change. Where the string passed is the name of the Property (use reflection/pull the property name from the stack trace :- means the code in each method can be precisely the same) ... and the object passed is simply the meta variable 'value'. Some careful reflection/stack trace checking might mean you can remove the string parameter on this method ... means you keep entity Class C# coding requirements to a minimum.

The flag is there because basic state initialisation of the object means that property changes (set accessor calls) may be made until the object is fully hydrated the first time.

The Dictionary is there to enable trawling the changes (auditing?) and so forth. Scale this back to a second bool if all you need is simple true/false on the 'IsDirty' question.

Something like:

public abstract Class EntityBase
{
    private bool _changesAreTracking = false;
    private Dictionary<string, object> _changes = null;
    public EntityBase() {}

    public TrackChange(string propertyName, object value)
    {
        if(_changesAreTracking)
        {
            if(_changes == null) { _changes = new Dictionary<string, object>(); }

            _changes.Add(propertyName, value);
        }
    }

    public void StartTrackChanges()
    {
        _changesAreTracking = true;
    }

    public bool HasChanged()
    {
        bool returnThis = false;

        if(_changes != null && _changes.Keys.Count() > 0)
        {
            returnThis = true;
        }

        return returnThis;
    }

    public bool HasChanged(string propertyName)
    {
        bool returnThis = false;

        if(_changes != null && _changes.Keys.Contains(propertyName))
        {
            returnThis = true;
        }

        return returnThis;
    }
}
Aidanapword