Different ways to implement 'dirty'-flag functionality

Viewed 23571

Almost every programmer did it once in his life: setting some flag if a variable's value changed. There's always lots of properties and you want to keep track if something changed

  1. in any property
  2. in a specific property
  3. or in some set of properties

I'm interested in different ways to implement the "dirty-flag" functionality for the above situations, besides the standard object wide dirty flag being updated on each property change. There must be something better than putting "dirty = true" in each setter: it just looks ugly and is a tedious work.

8 Answers

For my DAO I keep a copy of the original values as retrieved from the database. When I send it to be updated, I simply compare the original values with the current. It costs a little in processing but it is a lot better than having a dirty flag per property.

EDIT to further justify not having a dirty flag: if the property returns to its original value, there is no way to reflect that, the dirty flag continues dirty because the original value was lost.

I used to have a base Entity class, providing Dirty/Removed Logic.

When writing Entity-subclasses, you could do something like:

public string Name
{
    get { return name; }
    set { setValue("Name", value); }
}

This works fine, but has the 'ugly string' disease...

Today you can use Lambda Expressions to exclude the strings:

set {setValue(x => x.Name, value);}

Or, and I think that this is the best solution, you could use AOP:

https://www.postsharp.net/

This way, you can define actions by Attributes. You create an attribute and specify that when the user changes the associated property, the entity becomes dirty.

Additionally, you can keep a list of properties in your class (base Entity) which will remember the changed properties, and access that list from your AOP Code.

I've created a class called DirtyValue<T> which has an original value and a current value. On its first use it sets both the original value and the current value. Successive calls only set the current value.

You can tell if it has changed by comparing the two, with a readonly bool property called IsDirty(). Using this technique you can also get access to the original value as well.

If you are setting a "dirty" flag realize that you are keeping state. At some point you need to take an action based on that state, otherwise you wouldn't need to keep the flag. So the question then becomes: is there another way to trigger the needed action? Sending messages of some kind? Who consumes the "dirty" state and takes action, and is there a cleaner interface for that notification?

In some situations with a data writer task and an independent reader task, I've given each task an updateCount variable. The producer increments its count whenever it writes. Whenever the reader wakes up and finds its count less than the producer's count, it does an update with the current values. You need a little special handling for counter overflow, but this is pretty simple to implement.

I've successfully used this technique in simulations - where the producer is the physics loop and the reader is the 3d display.

I would put changed() in each setter, i.e. call a private method instead of just changing a flag. The method may then set a flag or do whatever processing is needed, e.g. it could also notify any observers.

An interesting alternative to the explicit dirty=true approach, although it is probably overkill for most situations and often not applicable, would be to use guard pages. Set the memory page as read-only (e.g. with VirtualProtect() on Windows) and catch the signal/exception when the program tries to write to the page. Make a record that the page has been modified, then change the protection flags of the page to writable and resume execution.

This is the technique usually employed by operating systems to determine whether a page needs to be written to the swap file before it is evicted from RAM.

You may want to look at overriding the gethashcode and equals methods of your domain objects and storing the original hashcodes in a hashtable by object key. Then create a process that takes an object, find its key in the hashtable and compares hash values.

  • If hash same, no change. (do not send to repository or database)
  • if hash different, object has changes. (update)
  • If key not found, object is new. (insert)
  • Not sure how to determine if object needs to be deleted other than process delete on request and not using hashcode tracking for them.

I have not tried this and a hashtable may not be the best way to track object keys/hash values. It would save mem by tracking only hash codes and keys only. I am not 100% sure, but I think some orm's may use this method in their data context/tracking objects.

Related