简体   繁体   中英

Base Class Awareness of Property Changes in Derived Classes

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.

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_06.html

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 (eg with the State pattern) or find an alternative approach.

(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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM