Sunday 4 September 2011

Passing Anonymous Types as parameters

It's been a long while since my last C# post, so time for a short one.
Some days ago, I'm not sure why, it came back to my mind a question done by a colleague some months ago "hey, I can't pass Anonymous Types to another method?" and my simple answer, "no, you can't".

Well, my answer was rather simplified and outdated, what I really meant was that you can't pass Anonymous types around in a useful way. As the type is anonymous, when you pass it to another method, all you can put in the signature is Object, so in order to get access to any of its properties you would have to use Reflection, and that's verbose and slow.

public static void PrintPersonAnonymous(object p)
{
PropertyInfo propName = p.GetType().GetProperty("Name");
string name = (string)(propName.GetValue(p, null));
Console.WriteLine(name);
}

PrintPersonAnonymous(new
{
Name = "Iyan",
Age = 40
});


Hopefully, with C# 4.0 things are much better. You can declare the parameter as dynamic in the method signature, and then you can access its properties normally. The only problem is that the access is still done via Reflection, but it's the compiler who generates the code instead of you.

public static void PrintPersonDynamic(dynamic p)
{
string name = p.Name;
Console.WriteLine(name);
}

PrintPersonDynamic(new
{
Name = "Iyan",
Age = 40
});



Of course, we all know that dealing with Dynamic objects can be pretty fast if we're using objects that take care themselves of the property access - method invocation by implementing IDynamicMetaObjectProvider, like for example ExpandoObject does.

With what I've just said, an idea comes to mind, converting an anonymous type into a ExpandoObject, something that is pretty trivial (probably the most interesting thing here is that we can get access to a Property of the ExpandoObject using its string name by leveraging that it implements IDictionary<String,Object>)


public static dynamic AnonymousToDynamic(object ob)
{
IDictionary d = new ExpandoObject();
foreach(PropertyInfo property in ob.GetType().GetProperties())
{
d[property.Name] = property.GetValue(ob, null);
}
return d as dynamic;
}


This way we can convert our anonymous object to an ExpandoObject to improve performance.

The source code

Ah, while writing this I found this post where they explain a rather different approach to this same problem.



No comments:

Post a Comment