Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Mapping Properties to String Keys

0.00/5 (No votes)
1 Oct 2014 1  
PropertyMapper allows mapping object properties to string keys and accessing property values based on those string keys

Introduction

PropertyMapper<T> is a helper class that allows to map object properties to a certain string keys. It also allows to access values of mapped properties based on those string keys.

I first needed such functionality while working with EntityFramework Code-First. I had a few table structures with many columns having uppercase names and containing underscores, which I didn't want to bring into my POCO object definitions. So I decided to create a helper class that would map my POCO object properties to the string keys ones, and would let me extract values from POCO instances and quickly map them back to original string keys, forming a dictionary with key/value pairs.

Background

Mapping functionality by itself is pretty trivial, it is based on two instances of Dictionary<string, string> for quick lookup, and does not require special attention. What's more interesting here is the GetPropertyName method, which accepts Expression<Func<T, TReturn>> as an argument. This trick allows to use MapProperty method as follows:

public sealed class Test
{
    public string Foo { get; set; }
    public string Bar { get; set; }
}

var mapper = new PropertyMapper<Test>();
mapper.MapProperty(x => x.Foo, "PROP-FOO");
mapper.MapProperty(x => x.Bar, "PROP-BAR");

As opposed to passing hard-coded strings, that make code refactoring impossible:

mapper.MapProperty("Foo", "PROP-FOO");
mapper.MapProperty("Bar", "PROP-BAR");

Source Code

public sealed class PropertyMapper<T>
{
    private readonly Dictionary<string, string> m_maps = new Dictionary<string, string>();
    private readonly Dictionary<string, string> m_props = new Dictionary<string, string>();

    private static string GetPropertyName<TReturn>(Expression<Func<T, TReturn>> property)
    {
        var expr = property.Body as MemberExpression;
        if (expr == null)
            throw new InvalidOperationException("Invalid property type");
        return expr.Member.Name;
    }

    public void MapProperty<TReturn>(Expression<Func<T, TReturn>> property, string mapTo)
    {
        var propName = GetPropertyName(property);
        m_maps[mapTo] = propName;
        m_props[propName] = mapTo;
    }

    public string GetPropertyMap<TReturn>(Expression<Func<T, TReturn>> property)
    {
        return GetPropertyMap(GetPropertyName(property));
    }

    public string GetPropertyMap(string property)
    {
        string result;
        return m_props.TryGetValue(property, out result) ? result : null;
    }

    public object GetPropertyValue(T instance, string property)
    {
        string result;
        if (!m_maps.TryGetValue(property, out result))
            return null;
        return typeof (T).GetProperty(result).GetValue(instance, null);
    }

    public IDictionary<string, object> GetPropertyValues(T instance)
    {
        return m_maps
            .Select(x => new {Name = x.Key, Value = typeof (T).GetProperty(x.Value).GetValue(instance, null)})
            .Where(x => x.Name != null && x.Value != null)
            .ToDictionary(x => x.Name, x => x.Value);
    }
}

Using the Code

Given the following class:

public sealed class Test
{
    public string Foo { get; set; }
    public string Bar { get; set; }
}

We can use PropertyMapper<T> as follows:

var mapper = new PropertyMapper<Test>();

mapper.MapProperty(x => x.Foo, "PROP-FOO");
mapper.MapProperty(x => x.Bar, "PROP-BAR");

var t = new Test {Foo = "Value-Foo", Bar = "Value-Bar"};

Console.WriteLine("Single property:");
var propMap = mapper.GetPropertyMap(x => x.Foo);
Console.WriteLine("{0}={1}", propMap, mapper.GetPropertyValue(t, propMap));
Console.WriteLine();

Console.WriteLine("All properties:");
foreach (var item in mapper.GetPropertyValues(t))
    Console.WriteLine("{0}={1}", item.Key, item.Value);

Output results are:

Single property:
PROP-FOO=Value-Foo

All properties:
PROP-FOO=Value-Foo
PROP-BAR=Value-Bar

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here