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.