See also: Properties as objects

 

The goal here is to have a class with a property that implements the Observer pattern, based on a statement in Object Thinking that all classes should support this.  (I’m not sure I agree, but I’m exploring it anyway.)

 

So far I’ve proposed two options:

 

Let the class support its own notifications of events.  Downsides are:

  • Duplicated code as soon as another property wants the same feature.
  • 11 lines of text in my class to support the basic notion of an object with an attribute
  • Possibility of a bug where the class directly modifies the backing store, without firing the OnSet event.

 

Create a class to do it all for you.  Downsides are:

  • Can’t limit access to the setter to just the containing class.
  • Violates encapsulation rule of Law of Demeter by exposing an implementation detail (that I’m using Property<>).

 

Upon further discussion with members of the team, we’ve come up with something I like quite a bit.  It balances responsibilities between the class you’re writing and the Property<> class.  It seems to solve all the problems listed above.

 

Here’s the code:

 

      interface IReadonlyProperty<T>

      {

            T Value { get; }

            event Property<T>.SetEventHandler OnSet;

      }

 

      class Property<T> : IReadonlyProperty<T>

      {

            T _value;

 

            public Property()

            {

                  // put something into the event so that I don't have to check

                  // for null later.

                  this.OnSet += delegate { };

            }

 

            public delegate void SetEventHandler(object sender, T newValue);

 

            public event SetEventHandler OnSet;

 

            public T Value

            {

                  get

                  {

                        return this._value;

                  }

                  set

                  {

                        this._value = value;

                        this.OnSet(this, this._value);

                  }

            }

 

            public void SetValueWithoutFiringEvent(T t) { this._value = t; }

 

            T IReadonlyProperty<T>.Value { get { return this._value; } }

      }

 

To demonstrate its worth, here’s the usage:

 

      class Customer

      {

            Property<int> _age = new Property<int>();

 

            public IReadonlyProperty<int> Age

            {

                  get { return this._age; }

            }

 

            public void Test()

            {

                  int eventFiredCount = 0;

                  this._age.OnSet += delegate { eventFiredCount++; };

 

                  Debug.Assert(eventFiredCount == 0);

 

                  this._age.Value = 9;

                  Debug.Assert(eventFiredCount == 1);

 

                  this._age.SetValueWithoutFiringEvent(7);

                  Debug.Assert(eventFiredCount == 1);

            }

      }

 

Note that I can still set the value internally to Customer without firing the event, but only by explicitly saying that’s what I’m doing.  I could decide never to allow that by just removing the SetValueWithoutFiringEvent method.