ILoggable

A place to keep my thoughts on programming

 Subscribe

geekblog
[at]
claassen [dot] net

Powered by Blogger

Thursday, January 21, 2010

Duckpond: Lightweight duck-typing for C#

Edit: Changed As to AsImplementationOf since it's an extension method on object and too likely to collide.

A while back I was talking about Interface Segregation and proposed using either LinFu's DynamicObject or delegate injection. While I played a bit more with delegate injection, in practical use delegate injection turned out to be rather ugly and not really improve readability.

So, I've come back to wanting to cast an object to an interface regardless of what interfaces that object implemented. I wanted this to be as simple and lightweight as possible, so rather than using a dynamic proxy framework, i simply rolled my own IL and wrote a pure proxy that does nothing but call the identical method on the class it wraps.

Introducing DuckPond

DuckPond is a very simple and focused library. It currently adds only a single extension method: object.AsImplementationOf<Interface>

Given a class Duck that implements a number of methods, including Quack:

public class Duck {
  public void Quack(double decibels) {
    ...
  }
  ... various other methods ...
}
we can easily cast Duck to a more limited interface that the class doesn't implement such as:
public interface IQuacker {
  void Quack(double decibels);
}
using the object.AsImplementationOf<T> extension method:
using Droog.DuckPond;

...

var quacker = new Duck().AsImplementationOf<IQuacker>();
That's all there is to it.

But is it fast?

Honestly, i don't know yet. I have not benchmarked the generated classes against virtual method dispatches or LinFu's and Castle's dynamic proxy. I assume it is, since unlike with dyanmic proxy, DuckPond doesn't use an interceptor. Instead it emits Intermediate Language for each call in the interface, dispatching the call against the wrapped instance's counterpart.

Try it, fork it, let me know what you think

The code is available now at GitHub: http://github.com/sdether/duckpond

Labels: , , ,

Tuesday, July 10, 2007

A generic asynchronous INotifyPropertyChanged helper

The other day I was lamenting what I consider to be an omission in Data-binding's responsibilities, i.e. the lack of invocation of an INotifyPropertyChanged PropertyChanged event on the appropriate UI thread. Instead, INotifyPropertyChanged implementors are expected to be updated only on the UI thread in order to work.

I figured I should be able to throw a proxy between the actual INotifyPropertyChanged implementor and the binding, and have this proxy be instantiated with awareness of the observing form. Thus the proxy could do the invocation on the UI thread and still let me use INotifyPropertyChanged without creating a dependency on knowing that the object was being observed by a UI element. That line of thought lead to worked as a static proxy, that I had to create by hand. Once I switched to Castle's Dynamic Proxy, it didn't work anymore, the event somehow being swallowed along the way.

I also considered looking at creating my own BindingContext but that didn't bear fruit either. It was then that I realized that I didn't need to create a proxy that matched my source object, since data binding didn't care what it bound to, as long as it had the dataMember it was being told about. I started down a path of creating a wrapper class using Reflection.Emit when I further reasoned that even the dataMember that's exposed doesn't have to match the one of the data source. This opened the door to just using dynamic property invocation and a simple generic helper class emerged:

using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Windows.Forms;

namespace FullMotion.Helpers
{
  /// <summary>
  /// A helper class for creating a binding on an object that may be changed
  /// asynchronously from the bound UI thread.
  /// </summary>
  public class AsyncBindingHelper : INotifyPropertyChanged
  {
    /// <summary>
    /// Get a binding instance that can invoke a property change
    /// on the UI thread, regardless of the originating thread
    /// </summary>
    /// <param name="bindingControl">The UI control this binding is added to</param>
    /// <param name="propertyName">The property on the UI control to bind to</param>
    /// <param name="bindingSource">The source INotifyPropertyChanged to be
    /// observed for changes</param>
    /// <param name="dataMember">The property on the source to watch</param>
    /// <returns></returns>
    public static Binding GetBinding( Control bindingControl,
                                      string propertyName,
                                      INotifyPropertyChanged bindingSource,
                                      string dataMember )
    {
      AsyncBindingHelper helper 
        = new AsyncBindingHelper(bindingControl,bindingSource,dataMember);
      return new Binding(propertyName,helper,"Value");
    }

    Control bindingControl;
    INotifyPropertyChanged bindingSource;
    string dataMember;

    private AsyncBindingHelper( Control bindingControl,
                                INotifyPropertyChanged bindingSource, 
                                string dataMember )
    {
      this.bindingControl = bindingControl;
      this.bindingSource = bindingSource;
      this.dataMember = dataMember;
      bindingSource.PropertyChanged 
        += new PropertyChangedEventHandler(bindingSource_PropertyChanged);
    }

    void bindingSource_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
      if (PropertyChanged != null && e.PropertyName == dataMember)
      {
        if (bindingControl.InvokeRequired)
        {
          bindingControl.BeginInvoke(
            new PropertyChangedEventHandler(bindingSource_PropertyChanged),
            sender,
            e );
          return;
        }
        PropertyChanged(this, new PropertyChangedEventArgs("Value"));
      }
    }

    /// <summary>
    /// The current value of the data sources' datamember
    /// </summary>
    public object Value
    {
      get
      {
        return bindingSource.GetType().GetProperty(dataMember)
          .GetValue(bindingSource,null);
      }
    }
    #region INotifyPropertyChanged Members
    /// <summary>
    /// Event fired when the dataMember property on the data source is changed
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;

    #endregion
  }
}

To use this class, simply replace this:

myLabel.DataBindings.Add("Text", myDataSource,"MyProperty");
with this:
myLabel.DataBindings.Add(
  AsyncBindingHelper.GetBinding(myLabel, "Text", myDataSource,"MyProperty") );

The one tricky thing about this is that it may cause uncollectable references. We're creating an instance of AsyncBindingHelper behind the scenes that sets up an event handler on our binding source. Which means we can't get rid of that event subscription. Theoretically, once the binding control goes out of scope, the helper should also go out of scope, relinquishing the reference it holds on the binding source.

The other thing that would be simple to do is to turn this helper into an Extension Method on INotifyPropertyChanged, once I move my code over to Orcas. That way creating an asynchronous binding on an instance of INotifyPropertyChanged would become even cleaner and straight forward.

Labels: , , , ,