Click here to Skip to main content
15,886,578 members
Articles / Programming Languages / C#
Tip/Trick

Mapping Properties to String Keys

Rate me:
Please Sign up or sign in to vote.
5.00/5 (6 votes)
1 Oct 2014CPOL 17K   14   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:

C#
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:

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

Source Code

C#
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:

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

We can use PropertyMapper<T> as follows:

C#
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 5 Pin
StM0n5-Oct-14 18:45
StM0n5-Oct-14 18:45 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.