开发者

What is the best practice to check if an object is changed?

I need to know how do you check if an object is changed. Basically I need something like a property that is named TrackChanges, when I set it true once and if any data within this object is "changed", a method on the same object (IsObjectChanged) can return true.

Did you ever needed such a thing and how did you solve it? I do not want to invent the wheel if there is already a best-practice for such scenario?

I was thinking to clone the object before I call TrackChange=true, in its setter. And when I call Is开发者_C百科ObjectChanged() By using reflection I will compare all the public field values of it with the cloned copy. I am not sure if it is a good way.

Any advices?

thanks, burak ozdogan


When I need to track changes to properties on my objects for testing I hook an event handler on the objects PropertyChanged event. Will that help you? Then your tests can do whatever action they want based on the change. Normally I count the number of changes, and add the changes to dictionaries, etc.

To achieve this your class must implement the INotifyPropertyChanged interface. Then anyone can attach and listen to changed properties:

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++;
    }
}


There are two parts to this. Events for change notification are one piece, but maintaining history is another important piece. Entity Framework does this too (as does LINQ to SQL), and I've implemented this in my own code as well. At minimum, you keep a flag for a member to say that it has changed. Depending on your requirements, you may keep the original value as well. This usually becomes the task of a separate object. Entity Framework keeps its change tracking in a separate object (EntityState, if I remember correctly).

In my own code, I developed a "DataMember" class that not only held the values, but also kept change flag, null status, and various other useful things. These DataMembers were private members in an Entity class, and the Entity provided properties that exposed the data as simple data types. The property get and set methods interacted with the DataMember to "do the right thing", but the DataMember did change tracking. My Entity class inherited from an "EntityBase" class that provided methods to check for change at the entity level, accept changes (reset change flags), etc. Adding change notification will be the next thing I do, but having a DataMember class for individual data elements, and an EntityBase to own the change notification event handler, will simplify this a lot.

EDITED TO ADD:

Now that I'm at work, I can add some code samples. Here's the interface definition for my DataMember class:

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

Here's a typical property in an entity class:

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

Note that the DataMember can support properties as nullable, or not.

Constructor code to add a DataMember:

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


Burak ,

You might take a look at the Entity Framework or the other framework of Microsoft. You can see events like PropertyChanging or PropertyChanged.

Take a look at the generated code.

You might take a look at the NHibernate code as well , but since the code base is so huge, better to look at the Microsoft ORM generators..


Implement and use the interface INotifyPropertyChanged. A cool way to do that without string literals is here.


Why don't you create a List and put your first object in, then you can compare it to the current object by using a simple comparison.

As above you can use INotifyPropertyChanged to see what properties have changed in your object.


Instead of creating a property you should be creating an event and call it something like OnChanged.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜