views:

82

answers:

3

I was wondering if anyone had a possible solution to the following problem... I have a base class that a series of derived classes will inherit from. The base class cares about whether properties on the derived class have changed. This is to set up an "IsDirty" approach for a data transfer object.

The traditional approach would be to set an IsDirty boolean flag declared in the base class. I was hoping to avoid this somehow, and was wondering if there might be another approach? I am concerned about a developer not remembering to set the flag in the equivalent set operation on a property in the derived class. I had considered the idea of creating a generic "SetProperty" method that would take the property name and value, but thought that there might be something more elegant.

Just as a side note, ideas regarding using reflection are not a problem. Regardless of the expense of reflection, I would like to prove out a way to do it and work on refining it further on down the road.

+1  A: 

An appropriate pattern for controlling access to a class (or a set of classes) is the Proxy pattern. This pattern would allow you to implement the correct isDirty behavior once at the proxy level and delegate any read-only behavior to the real instance unchanged.

This pattern is most effective when used with a Factory pattern to control creation of the instances.

This solution will mask the run-time type of the instance, so if your design relies on run-time type information you will either need to solve this problem separately (e.g. with the State pattern) or find an alternative approach.

richj
Definitely an interesting approach, but I do require run-time type information (namely "discovery services" that consume these objects). I do not know why I didn't consider the State pattern, as it seems pretty obvious in hindsight now. :-)
joseph.ferris
+1  A: 

Can you force the derived classes to implement INotifyPropertyChanged? In that case I'd add a listener to the PropertyChanged event in the base class constructur and chill. The derived class now still needs to follow the pattern (which might be something you want to avoid?).

Nice read for a "no literal strings used" approach for raising the property changed events: http://monotorrent.blogspot.com/2009/12/yet-another-inotifypropertychanged-with%5F06.html

Benjamin Podszun
Wow. What an elegant way of solving the problem! I had looked at the INotifyPropertyChanged interface, but most of the examples I could find still depended on each setter having additional code.
joseph.ferris
As far as having to do the work in the derived class, I do not mind. I was well prepared that there would not be a full "magic bullet" solution but the pros of doing it this way, by far, outweigh the cons. I'll give it a try and likely mark this as the answer.
joseph.ferris
Works beautifully! Thank you very much.
joseph.ferris
A: 

(Quick & Dirty) - What about something like this? (Your implementation of GetHashCode may vary - I used ReSharper to auto-generate this one)

    public abstract class Animal
    {
        private int _originalHash;

        public string Name { get; set; }
        public int Age { get; set; }

        public Animal(string name, int age)
        {
            this.Name = name;
            this.Age = age;

            this._originalHash = GetHashCode();
        }


        public override sealed int GetHashCode()
        {
            unchecked
            {
                return ((Name != null ? Name.GetHashCode() : 0) * 397) ^ Age;
            }
        }

        public bool IsDirty
        {
            get
            {
                return this._originalHash != GetHashCode();
            }
        }
    }

    public class Cat : Animal
    {
        public Cat(string name, int age)
            : base(name, age)
        {
        }
    }

Used this to test...

var cat = new Cat("BobTheCat", 12);
Console.WriteLine(cat.IsDirty);
cat.Age = 13;
Console.WriteLine(cat.IsDirty);

Results were:

False True

zincorp
Nice approach, and I could see how that would work well. Only problem that I have with this approach is that it is an "all or nothing" approach. I did not specify in the original question, but there is the distinct possibility that some properties might not be tracked for changes.
joseph.ferris