Object Recycling

It is common in Update Controls to use linq to specify a list of view models. For example:

public IEnumerable<ContactViewModel> Contacts
{
    get
    {
        return
            from c in _addressBook.Contacts
            select new ContactViewModel(c);
    }
}

As you might imagine, this code runs every time a contact is added or deleted. Each time, it rebuilds the entire list. How is this not a performance problem?

The recycle bin

Internally, Update Controls uses object recycling. It will reuse objects from one run to the next. It does so by adding objects to a RecycleBin<T>. Then it extracts from that recycle bin as it processes new objects.

using (var bin = new RecycleBin<ContactViewModel>())
{
    foreach (ContactViewModel oldContact in _contacts)
        bin.AddObject(oldContact);
    _contacts.Clear();

    foreach (ContactViewModel newContact in _viewModel.Contacts)
        _contacts.Add(bin.Extract(newContact));
}

All of the old objects are added to the recycle bin. Then the original collection is cleared. New objects are extracted through the recycle bin before being added back into the collection. If the object is already in the recycle bin, the old one is returned. If not, the new one is used.

Equals and GetHashCode

The recycle bin uses the Equals and GetHashCode methods to find existing objects. So for this to have the desired effect, we have to implement these methods in ContactViewModel:

public override bool Equals(object obj)
{
    if (obj == this)
        return true;
    ContactViewModel that = obj as ContactViewModel;
    if (that == null)
        return false;
    return _contact.Equals(that._contact);
}

public override int GetHashCode()
{
    return _contact.GetHashCode();
}

So even though we create a new list of ContactViewModels on every update, we reuse the old ones for the Contacts that were not added or removed.

The main advantage of object recycling is that dependent properties are preserved. None of the ContactViewModel properties need to be recalculated on the recycled objects. If ContactViewModel has any children, then those are preserved as well. This can be a significant savings for deep hierarchies.

Managing external resources

Another advantage of object recycling is that it can be used to manage an external resource. Suppose we want to represent each contact with a 3D object in a DirectX scene graph. We’ll add the following methods to ContactViewModel:

private Mesh _mesh;
private SceneGraph _sceneGraph;

public void EnsureInSceneGraph(SceneGraph sceneGraph)
{
    if (_mesh == null)
    {
        _mesh = new Mesh();
        _sceneGraph = sceneGraph;
        _sceneGraph.Add(_mesh);
    }
}

public void Dispose()
{
    if (_mesh != null)
    {
        _sceneGraph.Remove(_mesh);
    }
}

We call these methods while updating the collection.

using (var bin = new RecycleBin<ContactViewModel>())
{
    foreach (ContactViewModel oldContact in _contacts)
        bin.AddObject(oldContact);
    _contacts.Clear();

    foreach (ContactViewModel newContact in _viewModel.Contacts)
    {
        ContactViewModel extracted = bin.Extract(newContact);
        extracted.EnsureInSceneGraph(_sceneGraph);
        _contacts.Add(extracted);
    }
}

As we extract objects from the recycle bin, we ensure that the mesh is in the scene graph. If the object was already there, then nothing happens. If this is a new object, then the mesh is created.

When we leave the using block, the recycle bin is disposed. This in turn disposes all objects that were not removed from the recycle bin. An object is left over if it used to be in the collection, but it was removed. So we remove the mesh in the Dispose method.

Update Controls uses object recycling to improve performance and manage external resources. Be sure to implement Equals and GetHashCode to work well with it. And if you need some extra performance, or you need to manage your own external resources, you can use the same technique.

Comments

Alternative to code generation

After installing Update Controls, I couldn't find the helper-thingie that generates properties for private fields in Visual Studio 2008. But that's okay. I am allergic to code generators anyway. So I came up with an alternative:

   public class Independent<T>
   {
      public Independent() { }
      public Independent(T initialValue) { _value = initialValue; }

      public readonly Independent IndependentSentry = new Independent();

      protected T _value;
      public T Value
      {
         get { IndependentSentry.OnGet(); return _value; }
         set { IndependentSentry.OnSet(); _value = value; }
      }
      
      public static implicit operator T(Independent<T> i)
             { return i.Value; }
   }

   public class Dependent<T>
   {
      public Dependent(Func<T> computeValue)
      {
         _computeValue = computeValue;
         DependentSentry = new Dependent(() => _value = _computeValue());
      }

      public readonly Dependent DependentSentry;
      Func<T> _computeValue;

      T _value;
      public T Value
      {
         get { DependentSentry.OnGet(); return _value; }
      }

      public static implicit operator T(Dependent<T> d) { return d.Value; }
   }

With these classes defined, I can define sentry-backed properties like so:

   private Independent<string> _name = new Independent<string>();
   private Independent<DateTime> _date = new Independent<DateTime>();

   public string Name
   {
      get { return _name; }
      set { _name.Value = value; }
   }
   public DateTime Date
   {
      get { return _date; }
      set { _date.Value = value; }
   }

Sure, I still have to write the properties by hand, but I'm used to that, and it's still less work than implementing INotifyPropertyChanged.

I could "cheat" to make the code shorter:

   public Independent<string> Name { get; private set; }
   public Independent<DateTime> Date { get; private set; }
   public Model()
   {
      Name = new Independent<string>();
      Date = new Independent<DateTime>();
   }

Unfortunately, this would often force callers to access the Independent<T>.Value property themselves, so this solution seems messier overall.

I'd like to include your patch

I've decided that I should add your classes to the core library. Could you please post your name so I can credit you?

Thanks.

Intriguing

I've rejected using generics like that in the past, but it certainly does clean things up. I might just add it to the library after all.

My biggest concern is that someone might accidentally do something like Independent<List<Child>> and be surprised when it doesn't work. But then again, I just recently added IndependentList<Child>, so I guess the danger is reduced.

Let me mull that over.

David Piepgrass

...is my name.

Dependent<List<T>> works okay (as long as it's treated as read-only outside the updater)... I tried replacing the list of Blog._tags in Noteworthy demo with Dependent<List<Tag>>, and this works fine.

But if you use Independent<List<T>>, adding/removing an item in the list causes OnGet() to be called when it should be OnSet(). You could do an assert in the Independent<T> constructor to make sure that T doesn't implement ICollection<*> (well, I'm not sure how to check that... some sort of reflection madness). Then again, ICollection should be fine if the collection IsReadOnly. Also, IEnumerable is not a problem, e.g. System.String implements it.