Andy Kutruff

Blog

Reactive Programming in C#: ReactiveObject

Posted by Andy Kutruff on July 14, 2009

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.

About these ads

23 Responses to “Reactive Programming in C#: ReactiveObject”

  1. Andy Chambers said

    It would be cool if you could define those rules on a “per-object” basis instead of a “per-class” basis? Also seems a pain to have to write a method for each slot that broadcasts it’s state change.

    Have you seen this?

    http://common-lisp.net/project/cells/

    IMO, this library alone is worth learning Lisp for

    • The “broadcast” is part of INotifyPropertyChanged, which everyone has to do anyway. You can use things like PropFu (a plugin to PostSharp) to automatically implement this interface for you.

      • Andy Chambers said

        Fair enough, that would help. I love the whole data-flow “paradigm” and there’s loads of interesting work going on in this area. There are some interesting haskell libraries that provide similar features too. Nice to see C# people getting behind it too. From what I’ve heard, some of the recent additions to C# should make implementing this kind of thing a little easier.

        For comparison, here’s your example in cells (though to be honest, this example doesn’t really push it’s limits).

        (defmd person ()
        (brother (c-in nil))
        (age)
        (age-difference (c? (- (age self)
        (age (^brother))))))

        That (c?…) declares that age-difference is dependent on (age self) and (age (^brother)), according to the specified formula. Now, when you make a person object, and update the “brother” slot (or the age slot), age-difference (and similarly any further slots in other objects that are dependent on age-difference) is automatically updated in response.

  2. Andy, I asked AK about having dependson defined in the instance instead of the type. After some talk, it was concluded that it was there for some good reasons (though I don’t remember why…) and we also decided that in cases the per instance would have been handy, those classes needed refactoring and failed to follow SOLID.

  3. sam said

    a bit off topic, but the column width on this post is so low that you can’t actually view all of your code without scrolling back and forth (running Firefox 3.0.11)

  4. Jeff Brown said

    Looks interesting.

    Consider encapsulating the full duration of the registration process. Right now it might not make any difference but later on you may discover additional opportunities for error checking or optimization because you know when the full list of dependencies has been prepared (and so cannot possibly change moving forward). For example, you might want to emit some DynamicMethods to speed things up down the line.

    eg.

    Register(dependsOn =>
    {
    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);
    });

  5. Extenze said

    I don’t usually reply to posts but I will in this case. I’ve been experiencing this very same problem with a new WordPress installation of mine. I’ve spent weeks calibrating and getting it ready when all of a sudden… I cannot delete any content. It’s a workaround that, although isn’t perfect, does the trick so thanks! I really hope this problem gets solved properly asap.

  6. Great stuff! Are there any plans to start accepting null or string.Empty as the PropertyName in the PropertyChanged event handler? Currently I get an ArgumentNullException.

    This is a valid scenario per the MSDN documentation:
    “The PropertyChanged event can indicate all properties on the object have changed by using either null reference (Nothing in Visual Basic) or String.Empty as the property name in the PropertyChangedEventArgs.”

  7. Raul Rangel said

    Awesome Lib!

    I was wondering if the Reactive object supported listening to Properties of Properties ?
    i.e)

    class Group : INotifyPropertyChanged, INotifyPropertyChanging {
    protected SecurityItemState _State;
    public SecurityItemState State {
    get {
    return _State;
    }
    set {
    if (_State != value)
    {
    OnPropertyChanging("State");
    _State = value;
    OnPropertyChanged("State");
    }
    }
    }
    }

    class GroupViewModel : ReactiveObject {
    Group _group;
    private Group Group {
    get { return _Group; }
    }
    static GroupViewModel(){
    var dependsOn = Register();

    dependsOn.Call(me => me.UpdateLoading())
    .OnChanged(me => me.Group.State)
    }
    private void UpdateLoading() { }
    }

    When I update the state on Group it never calls the UpdateLoading. Just wondering if there was a fix for that ?

    Thanks

    • kutruff said

      Yes, ReactiveObject supports multilevel property changes very nicely, and even handles nulls that may appear in the property access chain. In your code above, GroupViewModel does not call OnPropertyChanging(“Group”) or OnPropertyChanged(“Group”) anywhere. Every property you implement needs to fire changing and changed. I’ll be updating PropFu soon with my new version that automatically implements both interfaces for you.

      • Raul Rangel said

        Oh it all makes sense now. I omitted it when I first created the class cuz the property never changes after construction. But your code registers everything in the static constructor so of course it needs to throw an event once it’s been set otherwise the reactive class never knows.
        Brilliant!

        I got one more for you ;)

        I have a class that maintains a global list of all my objects. I want to monitor each object in those collections and when one of their properties gets changed I want to call my event.
        i.e)

        public class DataFacade {
        private SecurityCollection _GroupRelations;
        private SecurityCollection _Groups;
        // etc

        public SecurityCollection Groups {
        get { return _Groups; }
        internal set {
        OnPropertyChanging("Groups");
        _Groups = value;
        OnPropertyChanged("Groups");

        _Groups.CollectionChanged += new NotifyCollectionChangedEventHandler(_Groups_CollectionChanged);
        }
        }

        void _Groups_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) {
        switch (e.Action) {
        case NotifyCollectionChangedAction.Add:
        foreach (Object newItem in e.NewItems) {
        ((SecurityObject)newItem).PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(DataFacade_PropertyChanged);
        }
        break;
        // etc
        }
        }

        void DataFacade_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) {
        if (e is Group) {
        switch (e.PropertyName) {
        case "Parent":
        // Move item into new parent collection
        // Etc
        }
        } else if (e is GroupLevel) {
        // Same
        }
        //etc...
        }
        }

        Kinda same thing your library is trying to help avoid :)
        So I was wondering if there was a way to have the DataFacade Register each individual object so I can avoid doing the switch statements.

        Love the library!

        Raul

        • kutruff said

          CLINQ has a NotifyCollectionChangedMonitor that does exactly this. It has an ItemChanged event that will notify you when anything in your lambda expression changes. For example:

          var propertyAccessTree = ExpressionPropertyAnalyzer.Analyze(person => person.Age);
          var monitor = new NotifyCollectionChangedMonitor(propertyAccessTree, people);

          monitor.ItemChanged += (sender, item) => Console.WriteLine(((Person)item).Age);

          people[0].Age++;

          The above will print 19 to the console.

  8. Parva said

    hi
    i want all classes of this code, can u send it for me?

  9. Dan said

    I am trying to use your implementation of the reactiveObject with a mild twist. Instead of registering the events in the class or subclass i wanted to implement a stategy controller to the code. This would allow me to keep the models pretty simple and apply the business rules to the controllers. Can you let me know if its possible to user your ReactiveObject with the code I added below. I am hoping i am missing something very simple. I can’t seem to get the callback in the AddressStategyController.OnAddressChanged

    thanks,
    Dan

    public class ViewModelBase : ReactiveObject
    {
    // Inherit from reactiveObjet so i can add other methods to the base class that
    // are not part of reativeObject i.e. IDataErrorInfo
    }

    public interface IController { }

    public class StategyController : ViewModelBase, IController where T : class
    {
    public T Instance { get; set; }
    public StategyController() { }

    public StategyController(T instanceToBeControlled)
    {
    Instance = instanceToBeControlled;
    }
    }
    public class AddressStategyController : StategyController
    {
    static AddressStategyController()
    {
    var dependsOn = Register();

    // trying to register the change of City/State or zip to the
    //OnAddressChagned() callback
    dependsOn.Call(obj => obj.OnAddressChanged())
    .OnChanged(obj => obj.Instance.Address.City)
    .OnChanged(obj => obj.Instance.Address.State)
    .OnChanged(obj => obj.Instance.Address.Zip);
    }

    public AddressStategyController(MainWindowViewModel instance)
    {
    this.Instance = instance;
    }

    private void OnAddressChanged()
    {
    this.Instance.SingleLineAddress = this.Instance.Address.City + " " + this.Instance.Address.State + " " + this.Instance.Address.Zip;
    }

    }

    public class MainWindowViewModel : ViewModelBase
    {
    public readonly List Controllers = new List();

    static MainWindowViewModel()
    {
    var dependsOn = Register();
    dependsOn.Call(obj => obj.OnFullNameChanged())
    .OnChanged(obj => obj.FirstName)
    .OnChanged(obj => obj.LastName);
    }

    public MainWindowViewModel()
    {
    Address = new Address();
    Controllers.Add(new AddressStategyController(this));

    }

    public Address Address { get; set; }

    private void OnFullNameChanged()
    {
    this.FullName = this.FirstName + " " + this.LastName;

    }

    private string _firstName;
    public string FirstName
    {
    get { return _firstName; }
    set
    {
    OnPropertyChanging("FirstName");
    _firstName = value;
    OnPropertyChanged("FirstName");
    }
    }

    private string _lastName;
    public string LastName
    {
    get { return _lastName; }
    set
    {
    OnPropertyChanging("LastName");
    _lastName = value;
    OnPropertyChanged("LastName");
    }
    }

    private string _fullName;
    public string FullName
    {
    get { return _fullName; }
    set
    {
    OnPropertyChanging("FullName");
    _fullName = value;
    OnPropertyChanged("FullName");
    }
    }

    private string _singleLineAddress;
    public string SingleLineAddress
    {
    get { return _singleLineAddress; }
    set
    {
    OnPropertyChanging("SingleLineAddress");
    _singleLineAddress = value;
    OnPropertyChanged("SingleLineAddress");
    }
    }
    }

    public class Address : ViewModelBase
    {
    static Address()
    {
    var dependsOn = Register();
    dependsOn.Call(obj => obj.OnAddressChanged())
    .OnChanged(obj => obj.City);
    }

    private void OnAddressChanged()
    {
    // Simple test to prove it works at a per class level.
    this.State = City;
    }

    private string _city;
    public string City
    {
    get { return _city; }
    set {
    OnPropertyChanging("City");
    _city = value;
    OnPropertyChanged("City");
    }
    }

    private string _state;
    public string State
    {
    get { return _state; }
    set
    {
    OnPropertyChanging("State"); _state = value; OnPropertyChanged("State");
    }
    }

    private string _zip;
    public string Zip
    {
    get { return _zip; }
    set
    {
    OnPropertyChanging("Zip");
    _zip = value;
    OnPropertyChanged("Zip");
    }
    }
    }

  10. Tim said

    How does this compare to the System.Reactive assembly that is available in the Silverlight 3.0 Toolkit (2009-11)?

  11. […] […]

  12. Raim said

    How can I test this???

  13. […] to use Continuous LINQ library. You know it’s awesome! The huge work for us making the ReactiveObject. So you definitely should look at Continuous LINQ (if you didn’t have a chance already […]

  14. […] Continuous LINQ library. And you know it’s awesome! The huge amount of work for us making the ReactiveObject. You definitely should look at Continuous LINQ (if you didn’t have a chance already […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.

%d bloggers like this: