Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Expression for Type members results in different Expressions (MemberExpression, UnaryExpression)

Description

I have a expression to point on a property of my type. But it does not work for every property type. "Does not mean" means it result in different expression types. I thought it will ever result in a MemberExpression but this is not the case.

For int and Guid it results in a UnaryExpression and for string in a MemberExpression.

I am a little confused ;)

Some sample code

My class

public class Person {     public string Name { get; set; }     public int Age { get; set; } } 

Test Code

Person p = new Person { Age = 16, Name = "John" };  Expression<Func<Person, object>> expression1 = x => x.Age; // expression1.Body = UnaryExpression;  Expression<Func<Person, object>> expression2 = x => x.Name; // expression2.Body = MemberExpression; 

Question

How can i compare two expressions and check if they are mean the same type and same property ?

Update, Answer and complete Sample

Thanks to user dasblinkenlight who brought me on the right track.

He provided the method

private static MemberExpression GetMemberExpression<T>(     Expression<Func<T,object>> exp ) {     var member = expr.Body as MemberExpression;     var unary = expr.Body as UnaryExpression;     return member ?? (unary != null ? unary.Operand as MemberExpression : null); } 

I wrote the following extension method to compare the results of the GetMemberExpression methods and check if GetMemberExpression().Member.Name are the same.

private static bool IsSameMember<T>(this Expression<Func<T, object>> expr1, Expression<Func<T, object>> expr2) {     var result1 = GetMemberExpression(expr1);     var result2 = GetMemberExpression(expr2);      if (result1 == null || result2 == null)        return false;      return result1.Member.Name == result2.Member.Name; } 
like image 882
dknaack Avatar asked Oct 19 '12 13:10

dknaack


1 Answers

The reason this happens is that Age is a value type. In order to coerce an expression returning a value type into Func<Person,object> the compiler needs to insert a Convert(expr, typeof(object)), a UnaryExpression.

For strings and other reference types, however, there is no need to box, so a "straight" member expression is returned.

If you would like to get to the MemberExpression inside the UnaryExpression, you can get its operand:

private static MemberExpression GetMemberExpression<T>(     Expression<Func<T,object>> exp ) {     var member = exp.Body as MemberExpression;     var unary = exp.Body as UnaryExpression;     return member ?? (unary != null ? unary.Operand as MemberExpression : null); } 
like image 188
Sergey Kalinichenko Avatar answered Oct 16 '22 07:10

Sergey Kalinichenko