Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

How To Reference A Property By Name Without Using String Constants

DZone's Guide to

How To Reference A Property By Name Without Using String Constants

·
Free Resource

I’m working on some code here where I’m loading an entity using a dictionary. I’m not using .NET 4.0 so I’m not going to get to use the dynamic keyword and its IDictionary implementation of properties reflection.

My original code looked something sort of like this:

public void Populate(IDictionary<string, object> values) 
{
foreach (var kvp in values) {
var key = kvp.Key;
var value = kvp.Value;
switch (key)
{
case "FirstName":
this.FirstName = value;
break;
case "LastName":
this.LastName = value;
break;
// and so on and so forth
}
}
}


This looks sloppy. First of all, I don’t want to have to declare each and every property again for its setter just to support IDictionary. Secondly, what if I rename my properties? Then I’d have to go back and update this switch…case statement again. I want to use a strongly-typed property reference, so that if I rename the property I can use the IDE’s built-in refactoring functionality with which all uses of that property are automatically updated. I don’t get that benefit if I’m using string constants.

I’d come across some interesting tutorials in the past that addressed this problem, and I thought I’d give it my own go based on their insight. My revised solution is not by any means original. (Nothing I ever do is, I suppose.)

To make a long story short, I flexed some recently learned LINQ expression muscle on a member evaluator expression to obtain the strongly typed property’s name. The lambda expression I used isn’t pretty because of some mandatory casting to an expression, but it gets the job done in a more or less sanely-managed manner.

In my implementation (not entirely shown here) I actually do need to verify the property by name because I have a bunch of setter logic that I don’t expose here, such as replacing the value being an IEnumerable<string> with logic that clears an ObservableCollection<string> and populates it with the value. Anyway, here’s the basic flow:

public override void Populate(IDictionary<string, object> values)
{
foreach (var kvp in values) {
if (key == base.ResolvePropertyName((Expression<Func<object>>)(() => this.SpecialProperty)))
{
// this.SpecialProperty = value;
// do something special with setter here
}
else if (key == base.ResolvePropertyName((Expression<Func<object>>)(() => this.AnotherSpecialProperty)))
{
// this.AnotherSpecialProperty = value;
// do something special with setter here
}
else
{
base.Populate(key, value);
}
}
}

/// and in the base class ....

/// <summary>
/// Returns the name of the property. Syntax:
/// <code>
/// var propertyName = ResolvePropertyName((Expression<Func<object>>)(() => this.MyProperty))
/// </code>
/// </summary>
/// <param name="e"></param>
/// <returns></returns>
protected string ResolvePropertyName(Expression e)
{
if (e.NodeType == ExpressionType.Lambda)
{
return ResolvePropertyName(((LambdaExpression)e).Body);
}
if (e.NodeType == ExpressionType.MemberAccess)
{
return ((MemberExpression)e).Member.Name;
}
throw new InvalidOperationException("Given expression is not type MemberAccess.");
}

private static Dictionary<Type, List<PropertyInfo>> TypeProperties
= new Dictionary<Type, List<PropertyInfo>>();
/// <summary>
/// Populates a property of the current entity with the the given key/value pair.
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
public void Populate(string property, object value)
{
var t = this.GetType();
List<PropertyInfo> pis;
if (!TypeProperties.ContainsKey(t))
{
TypeProperties[t] = t.GetProperties().ToList();
}
pis = TypeProperties[t];
var pi = pis.Find(pif => pif.Name == property);
if (pi == null) throw new KeyNotFoundException("Property does not exist: \"" + property + "\"");
pi.SetValue(this, value, null);
}

The Populate(key,value) method is basic .NET 2.0 reflection with some sorta-kinda basic caching.  The method above it is using LINQ expressions to extract the member access invocation as expressed in the LINQ statement.

I wrote a unit test to invoke this and stepped through it with the debugger. Seems to work fine.

I’d actually really like to know how I can get rid of that messy cast from lambda to Expression in

ResolvePropertyName((Expression<Func<object>>)(() => this.AnotherSpecialProperty))

Seems like I missed something somewhere. Still, this should be a useful resource in the future.

Topics:

Published at DZone with permission of Jon Davis, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}