How to get property name from lambda
The whole idea is simple, we want this test to pass:
[Test]
void CanGetPropertyName_UsingLambda()
{
Assert.AreEqual("Name", PropertyName.For<person>(x => x.Name));
}
It seams nice and convenient way of getting property name.
Whole test fixture looks as follows:
[TestFixture]
public class PropertyNameTests
{
public string NameForTest { get; set; }
[Test]
public void CanGetPropertyName_SameType_UsingLambda()
{
Assert.AreEqual("NameForTest",
PropertyName.For(() => NameForTest));
}
[Test]
public void CanGetPropertyName_UsingLambda()
{
Assert.AreEqual("Name",
PropertyName.For<person>(x => x.Name));
Assert.AreEqual("Age",
PropertyName.For<person>(x => x.Age));
}
[Test]
public void CanGetPropertyName_Composite_UsingLambda()
{
Assert.AreEqual("Home.City",
PropertyName.For<person>(x => x.Home.City));
Assert.AreEqual("Home.FlatNumber",
PropertyName.For<person>(x => x.Home.FlatNumber));
}
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Home Home { get; set; }
}
public class Home
{
public string City { get; set; }
public string FlatNumber { get; set; }
}
Implementation uses .NET 3.5 feature called expression trees. Expression trees represent language-level code in the form of data. The data is stored in a tree-shaped structure.
/// <summary>
/// Gets property name using lambda expressions.
/// </summary>
internal class PropertyName
{
public static string For<t>(
Expression<func<t, object>> expression)
{
Expression body = expression.Body;
return GetMemberName(body);
}
public static string For(
Expression<func<object>> expression)
{
Expression body = expression.Body;
return GetMemberName(body);
}
public static string GetMemberName(
Expression expression)
{
if (expression is MemberExpression)
{
var memberExpression = (MemberExpression)expression;
if (memberExpression.Expression.NodeType ==
ExpressionType.MemberAccess)
{
return GetMemberName(memberExpression.Expression)
+ "."
+ memberExpression.Member.Name;
}
return memberExpression.Member.Name;
}
if (expression is UnaryExpression)
{
var unaryExpression = (UnaryExpression)expression;
if (unaryExpression.NodeType != ExpressionType.Convert)
throw new Exception(string.Format(
"Cannot interpret member from {0}",
expression));
return GetMemberName(unaryExpression.Operand);
}
throw new Exception(string.Format(
"Could not determine member from {0}",
expression));
}
}
UnaryExpression part is needed for value types to work.
April 1st, 2014 at 21:02
I think you have to modify GetMemberName at least a little, and put the following code in the begining
if (expression is LambdaExpression)
{
var lambdaExpression = (LambdaExpression)expression;
var compiled = lambdaExpression.Compile();
if (lambdaExpression.Body.NodeType == ExpressionType.MemberAccess)
{
return GetMemberName(lambdaExpression.Body);
}
}
April 2nd, 2014 at 08:43
Why?
April 2nd, 2014 at 12:48
Actually i maid a small mistake , you shoud pass expression.body in case of LambdaExpression, because LambdaExpression itself is not member expression and you’re code will throw an exception otherwise
April 5th, 2014 at 20:37
Could you write a unit test for this situation?
May 23rd, 2015 at 15:55
[…] ProtocolExHow to get property name from lambda Email template engine […]
September 22nd, 2015 at 10:51
Thanks, works perfectly. Just what I was looking for.