Skip to main content

Duck Typing with Anonymous Types

If you can create an anonymous method and an anonymous type, why not an 'anonymous class'? Wouldn't it be nice to be able to plug properties and methods into and object and then consume that object like any other class or interface?

What we're talking about is essentially duck typing (with strongly-typed ducks). There are examples all over of how to do this, especially with Castle Dynamic Proxy. This is my implementation of the same.

First let's look at a test:

public interface IDuck
{
    string Color { get; }
    Direction Fly();
    Direction Fly(Direction direction);
    string Quack();
}

[Test]
public void CanStubColorProperty()
{
    var rubberDuck = new { Color = "yellow" };
    var typedRubberDuck = rubberDuck.As<IDuck>();

    Assert.That(typedRubberDuck.Color == "yellow");
}

That As<IDuck> part is an extension method that does nothing right now, so this test will fail. What we want that extensions method to do is to return a proxy that implements the IDuck interface and forwards the method/property calls on to our anonymous type instance. Using Castle Dynamic Proxy, we can start creating this:

internal class DuckTypingInterceptor : IInterceptor
{
    private readonly object anonymous;

    public DuckTypingInterceptor(object anonymous)
    {
        this.anonymous = anonymous;
    }

    public void Intercept(IInvocation invocation)
    {
        if (invocation.IsGetter())
        {
            var property = invocation.PropertyName();
            invocation.ReturnValue = anonymous.GetPropertyValue(property);
        }
    }
}

There are some extension methods in there to help with reading method names and reflection, but it's pretty simple - when someone tries to get a property value from the proxy, we give back the value of the property on the anonymous object. Now we can implement that As<TDuck> extensions method:

public static TDuck As<TDuck>(this object anonymous) where TDuck : class
{
    var proxyGenerator = new ProxyGenerator();
    var objectImplementingDuckInterface =
        proxyGenerator.CreateInterfaceProxyWithoutTarget(typeof(TDuck), new DuckTypingInterceptor(anonymous));

    return objectImplementingDuckInterface as TDuck;
}

Now the test passes! Great, now what if that color property had a setter? Let's whip up some code to set the property on that anonymous type instance too:

[ ... some code that attempts to forward a setter invocation to the anonymous object via reflection ... ]
[Test]
public void CanSetColorProperty()
{
    var lameDuck = new { Color = "whocares" };
    var typedLameDuck = lameDuck.As<IDuck>();

    typedLameDuck.Color = "blue";

    Assert.That("blue" == typedLameDuck.Color);
}

The problem is, anonymous types don't have setters on the their properties. So we'll just set the backing field, right? Nope... anonymous type properties have readonly backing fields. They are immutable. We'd really like our proxy to behave like the interface it supposedly implements, so we hack around a bit and come up with this:

internal class DuckTypingInterceptor : IInterceptor
{
    private readonly object anonymous;
    private readonly IDictionary<string, object> properties = new Dictionary<string, object>();

    public DuckTypingInterceptor(object anonymous)
    {
        this.anonymous = anonymous;
    }

    public void Intercept(IInvocation invocation)
    {
        if (invocation.IsGetter())
        {
            var property = invocation.PropertyName();
            invocation.ReturnValue = GetPropertyValue(property);
        }

        if (invocation.IsSetter())
        {
            properties[invocation.PropertyName()] = invocation.Arguments[0];
        }
    }

    private object GetPropertyValue(string property)
    {
        if (properties.ContainsKey(property))
        {
            return properties[property];
        }

        return anonymous.GetPropertyValue(property);
    }
}

Now we're mixing in a dictionary of property values with the mutable anonymous object instance to give the feel of a single object with IDuck capabilities.

So what about methods? Well it would be nice if we could construct anonymous types with lambas, like

var duck = new
{
    Color = "white",
    Quack = () => "Quack!"
};

but if we try that, the compiler will yell at us because we "Cannot assign lambda expression to anonymous type property". There is something we can do, however, and I'll cover that in my next post.

Comments

Popular posts from this blog

Who I'm Is

I am a junior .NET developer currently working in Chicago, IL. I am starting this blog in order to enhance my knowledge of programming subject matter. Hopefully, someone else will be helped along the way. This first post will probably be edited soon...

Stubbing Static Methods with PostSharp

TypeMock uses the Profiler API to allow mocking, stubbing, etc. of classes used by code under test. It has the ability to handle sealed classes, static classes, non-virtual methods, and other troublesome-yet-oft-encountered scenarios in the world of unit testing. Other frameworks rely on proxies to intercept method calls, limiting them to be able to only fake virtual, abstract, and interface members. They also rely on dependecy injection to place the proxies as the concrete implementation of calls to the abstracted interface members. Anyone working with a legacy codebase is bound to run into static method calls (especially in the data access layer), dependencies on concrete types with non-virtual methods, and sealed class dependencies (HttpContext anyone?). The only way to unit test this without refactoring is with TypeMock. I've never used TypeMock, and I'm sure it's a great product, but it's not free. I decided to spike some code to see if I could solve the prob...

Strongly-Typed Property Constraints in Rhino Mocks

UPDATE: As I suspected, this functionality was right in front of my face – it’s called PredicateConstraint in Rhino Mocks. I also realize that I managed to completely ignore the existence of Predicate<T> in the framework, and write my own predicate delegate. Hey, I was on a roll. Rhino Mocks has a PropertyConstraint class that allows you to check the values on properties of objects passed into the method as part of the verification for that method being called. Unfortunately, the name of the property is specified as a string, which means the benefits of strong-typing that Rhino Mocks is normally so good at preserving are lost. Here’s an example (using Rhino Mocks 3.3 and .NET 2.0): [Test] public void Main_Form_Should_Show_Start_Panel_On_Load() { MockRepository mockRepository = new MockRepository(); IMainFormView mockView = mockRepository.DynamicMock<IMainFormView>(); IEventRaiser loadEventRaiser = GetEventRaiserFor(delegate { mockView.Load += null; });...