Thursday, April 03, 2008

Extension Properties for easy Reflection in C#

It's not generally considered good practice to define extension properties on object. But there's one scenario where I've found that it can be really nice. I've been copying the pattern of using anonymous types as dictionaries from the MVC Framework as described here by Eilon Lipton. This means you have to reflect over the anonymous type's properties to enumerate the dictionary. I've factored this reflection into an extension method for class:

public static IEnumerable<NameValue<string, object>> GetProperties(this object item)
{
    foreach (PropertyInfo property in item.GetType().GetProperties())
    {
        yield return new NameValue<string, object>(property.Name, () => property.GetValue(item, null));
    }
}

public class NameValue<TName, TValue>
{
    public TName Name { get; private set; }
    public TValue Value { get { return valueFunction(); } }

    Func<TValue> valueFunction;

    public NameValue(TName name, Func<TValue> valueFunction)
    {
        Name = name;
        this.valueFunction = valueFunction;
    }
}

Note that by using a lambda as the value in the NameValue class we defer actually accessing the value of the property until we need it.

Here's a test showing how you would use GetProperties:

[Test]
public void GetPropertiesShouldReturnThePropertiesOfAnAnonymousType()
{
    var item = new { Message = "Hello World", Number = 4 };

    Assert.AreEqual("Message", item.GetProperties().First().Name);
    Assert.AreEqual("Hello World", item.GetProperties().First().Value);
    Assert.AreEqual("Number", item.GetProperties().ElementAt(1).Name);
    Assert.AreEqual(4, item.GetProperties().ElementAt(1).Value);
}

3 comments:

Ruben Hakopian said...

That was really a bright solution for getting values from anonymous types.

Good job!

Mike Hadlow said...

Thanks Ruben!

mattmc3 said...

I know this is an old post, but I do something similar, but I do it in the form of a dictionary:


/// <summary>
/// Gets a dictionary of the property names and values for an object. Handy for converting
/// anonymous types to a dictionary.
///
public static IDictionary ToPropertiesLookup(this object o) {
IDictionary result = new Dictionary(StringComparer.OrdinalIgnoreCase);
if (o != null) {
foreach (System.ComponentModel.PropertyDescriptor descriptor in System.ComponentModel.TypeDescriptor.GetProperties(o)) {
object objVal = descriptor.GetValue(o);
result.Add(descriptor.Name, objVal);
}
}
return result;
}