Reactive Programming in C#: ReactiveObject

The company I work for has been using reactive programming for quite sometime, and I added our implementation to CLINQ a couple months ago (You can find it in by getting the latest source and finding the Reactive namespace.)  I noticed that Josh Smith, (who has an excellent WPF blog)  just posted something along the same spirit.  Of course, I quickly spammed the comments in his blog about ReactiveObject.  I figured I should give an explanation of how it works, and the various issues that you must deal with when solving this problem.

The infamous INotifyPropertyChanged requires classes to fire an event in each property’s setter with a string matching the property name.  Very often, other classes want to observe those property changes and execute code as a result. These other classes subscribe to the PropertyChanged and then have to examine the EventArgs and an inevitable switch statement or lookup table is used to map to an appropriate handler. This leads to hard coded strings, and messy messy code.  However, the spirit of this type of “reactive programming” is an excellent way to decouple your code, and is awesome for designing object models that hookup to WPF, or any other UI framework for that matter.  Here’s where ReactiveObject comes in which, I hope will change how you architect your front end applications.

Here’s an example of a Person class that follows this model. In this style of programming, an object wants to execute some code, or react, when properties change on itself or some other object.  (ReactiveObject implements INotifyPropertyChanged for you.) Let’s say we have Person object, and that person has Brother property which, of course, is another Person.  Now, whenever we change the Brother of a person we want to calculate the age difference between the two siblings.  Also, if someone changes the person’s age, we would need to do the same thing.  (I’m not going to deal with the circular reference situation for the sake of brevity,  but don’t worry that works too.)

Here’s how you would implement the Person class to make this happen.  (Explanation below)

        public class Person : ReactiveObject
        {
            static Person()
            {
                var dependsOn = Register<Person>();

                dependsOn.Call(me => me.OnMyAgeChanged())
                    .OnChanged(me => me.Age);

                dependsOn.Call(me => me.OnMyBrothersAgeChanged())
                    .OnChanged(me => me.Brother.Age);

                dependsOn.Call(me => me.UpdateAgeDifference())
                    .OnChanged(me => me.Age)
                    .OnChanged(me => me.Brother.Age);
            }

            private int _ageDifference;
            public int AgeDifference
            {
                get { return _ageDifference; }
                set
                {
                    if (value == _ageDifference)
                        return;
                    OnPropertyChanging("AgeDifference");
                    _ageDifference = value;
                    OnPropertyChanged("AgeDifference");
                }
            }

            private int _age;
            public int Age
            {
                get { return _age; }
                set
                {
                    if (value == _age)
                        return;
                    OnPropertyChanging("Age");
                    _age = value;
                    OnPropertyChanged("Age");
                }
            }

            private Person _brother;
            public Person Brother
            {
                get { return _brother; }
                set
                {
                    if (value == _brother)
                        return;
                    OnPropertyChanging("Brother");
                    _brother = value;
                    OnPropertyChanged("Brother");
                }
            }

            //Executed if this.Age changes, or if this.Brother.Age changes!
            private void OnMyAgeChanged()
            {
                Console.WriteLine("My age is now", this.Age);
            }

            //Executed if this.Brother changes, or if this.Brother.Age changes!
            private void OnMyBrothersAgeChanged()
            {
                Console.WriteLine("Brothers age is now", this.Brother.Age);
            }

            //Executed if this.Age, this.Brother, or this.Brother.Age changes!
            private void UpdateAgeDifference()
            {
                this.AgeDifference = this.Age - this.Brother.Age;
            }

        }

The real magic is in the static constructor of the Person object. This sets up how this object will react to property changes.  The first thing you do is call Register<Person> which returns a little object that you use to do registrations.  You use this registration object to define your relationships.  It uses a simple fluent interface that says: call this function on the object when a particular set of properties change.  Each lambda takes a me parameter.  Conceptually, me is the same as this if you ignored the fact that you’re in a static constructor. This is very important to the performance of the system, but understandably a little confusing at first.

The first example above says:  call OnMyAgeChanged whenever someone sets my Age property.

The next, and more interesting, example says:  call OnMyBrotherChanged whenever you set my Brother property, or if the Age property on my Brother changes.  The lambda expression you pass to OnChanged gets analyzed to any depth, and creates subscriptions on all the objects it encounters.  Also, brother can be null and nothing will break.

The final example shows how you can calculate something that depends on multiple values.  In this case the system will call UpdateAgeDifference when either the person’s Age, the person’s Brother, or the person’s Brother’s Age changes.  This means that your calculation will always be current no matter what changes underneath you.

Pretty nifty, no?  I’ve been part of team that has built an application on exactly this style of programming, and it has been a godsend.  All of your code is very decoupled, and information just flows through your program.

There are a few things to mention as to what’s going on behind the scenes.  First, all event subscriptions are weak and rely on CLINQ’s super fast property change manager.  (The one provided by WPF is slow.)  Next, the registration is done in the classes static constructor which means that there is only a one time hit for the lambda analysis and dependency map generation.  Also, you’ll notice that the handlers also require lambdas, which are open delegates rather than closures.  (Hence, this is why we have the me parameters.)  This is an important side effect of doing registration in the static constructor as closures will cause leaks, and ye olde memory fragmentation.