从lambda表达式中检索属性名称

是否有更好的方法来获得属性名时通过lambda表达式传递? 这是我目前拥有的。

如。

GetSortingInfo<User>(u => u.UserId);

它只在属性为字符串时才将其转换为成员表达式。因为不是所有的属性都是字符串,我必须使用object,但它会为那些返回一个unaryexpression。

public static RouteValueDictionary GetInfo<T>(this HtmlHelper html,
Expression<Func<T, object>> action) where T : class
{
var expression = GetMemberInfo(action);
string name = expression.Member.Name;


return GetInfo(html, name);
}


private static MemberExpression GetMemberInfo(Expression method)
{
LambdaExpression lambda = method as LambdaExpression;
if (lambda == null)
throw new ArgumentNullException("method");


MemberExpression memberExpr = null;


if (lambda.Body.NodeType == ExpressionType.Convert)
{
memberExpr =
((UnaryExpression)lambda.Body).Operand as MemberExpression;
}
else if (lambda.Body.NodeType == ExpressionType.MemberAccess)
{
memberExpr = lambda.Body as MemberExpression;
}


if (memberExpr == null)
throw new ArgumentException("method");


return memberExpr;
}
268857 次浏览

我最近做了一件非常类似的事情来创建一个类型安全的OnPropertyChanged方法。

下面是一个方法,它将返回表达式的PropertyInfo对象。如果表达式不是属性,则抛出异常。

public PropertyInfo GetPropertyInfo<TSource, TProperty>(
TSource source,
Expression<Func<TSource, TProperty>> propertyLambda)
{
Type type = typeof(TSource);


MemberExpression member = propertyLambda.Body as MemberExpression;
if (member == null)
throw new ArgumentException(string.Format(
"Expression '{0}' refers to a method, not a property.",
propertyLambda.ToString()));


PropertyInfo propInfo = member.Member as PropertyInfo;
if (propInfo == null)
throw new ArgumentException(string.Format(
"Expression '{0}' refers to a field, not a property.",
propertyLambda.ToString()));


if (type != propInfo.ReflectedType &&
!type.IsSubclassOf(propInfo.ReflectedType))
throw new ArgumentException(string.Format(
"Expression '{0}' refers to a property that is not from type {1}.",
propertyLambda.ToString(),
type));


return propInfo;
}

使用source参数,这样编译器就可以对方法调用进行类型推断。您可以执行以下操作

var propertyInfo = GetPropertyInfo(someUserObject, u => u.UserID);

好吧,没有必要调用.Name.ToString(),但大体上就是这样,是的。你唯一需要考虑的是x.Foo.Bar是否应该返回“Foo”,“Bar”,或者一个异常——也就是说,你是否需要迭代。

(re comment)关于灵活排序的更多信息,请参见在这里

我发现了另一种方法,就是让源和属性具有强类型,并显式地推断lambda的输入。不确定这是否是正确的术语,但这是结果。

public static RouteValueDictionary GetInfo<T,P>(this HtmlHelper html, Expression<Func<T, P>> action) where T : class
{
var expression = (MemberExpression)action.Body;
string name = expression.Member.Name;


return GetInfo(html, name);
}

然后像这样叫它。

GetInfo((User u) => u.UserId);

瞧,它起作用了。

我也在玩同样的东西,然后做了这个。它还没有完全测试过,但似乎处理了值类型的问题(你遇到的unaryexpression问题)

public static string GetName(Expression<Func<object>> exp)
{
MemberExpression body = exp.Body as MemberExpression;


if (body == null) {
UnaryExpression ubody = (UnaryExpression)exp.Body;
body = ubody.Operand as MemberExpression;
}


return body.Member.Name;
}

我在ObjectStateEntry上创建了一个扩展方法,以便能够以类型安全的方式标记(实体框架POCO类的)属性,因为默认方法只接受字符串。这是我从属性中获取名称的方式:

public static void SetModifiedProperty<T>(this System.Data.Objects.ObjectStateEntry state, Expression<Func<T>> action)
{
var body = (MemberExpression)action.Body;
string propertyName = body.Member.Name;


state.SetModifiedProperty(propertyName);
}

我已经完成了类似于下面方法的INotifyPropertyChanged实现。在这里,属性存储在基类中的字典中,如下所示。当然,使用继承并不总是可取的,但是对于视图模型,我认为它是可以接受的,并且在视图模型类中给出了非常干净的属性引用。

public class PhotoDetailsViewModel
: PropertyChangedNotifierBase<PhotoDetailsViewModel>
{
public bool IsLoading
{
get { return GetValue(x => x.IsLoading); }
set { SetPropertyValue(x => x.IsLoading, value); }
}


public string PendingOperation
{
get { return GetValue(x => x.PendingOperation); }
set { SetPropertyValue(x => x.PendingOperation, value); }
}


public PhotoViewModel Photo
{
get { return GetValue(x => x.Photo); }
set { SetPropertyValue(x => x.Photo, value); }
}
}

稍微复杂一些的基类如下所示。它处理从lambda表达式到属性名的转换。注意,这些属性实际上是伪属性,因为只使用了名称。但是它对于视图模型和视图模型上的属性引用来说是透明的。

public class PropertyChangedNotifierBase<T> : INotifyPropertyChanged
{
readonly Dictionary<string, object> _properties = new Dictionary<string, object>();


protected U GetValue<U>(Expression<Func<T, U>> property)
{
var propertyName = GetPropertyName(property);


return GetValue<U>(propertyName);
}


private U GetValue<U>(string propertyName)
{
object value;


if (!_properties.TryGetValue(propertyName, out value))
{
return default(U);
}


return (U)value;
}


protected void SetPropertyValue<U>(Expression<Func<T, U>> property, U value)
{
var propertyName = GetPropertyName(property);


var oldValue = GetValue<U>(propertyName);


if (Object.ReferenceEquals(oldValue, value))
{
return;
}
_properties[propertyName] = value;


RaisePropertyChangedEvent(propertyName);
}


protected void RaisePropertyChangedEvent<U>(Expression<Func<T, U>> property)
{
var name = GetPropertyName(property);
RaisePropertyChangedEvent(name);
}


protected void RaisePropertyChangedEvent(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}


private static string GetPropertyName<U>(Expression<Func<T, U>> property)
{
if (property == null)
{
throw new NullReferenceException("property");
}


var lambda = property as LambdaExpression;


var memberAssignment = (MemberExpression) lambda.Body;
return memberAssignment.Member.Name;
}


public event PropertyChangedEventHandler PropertyChanged;
}

当涉及到Array.Length时,有一个边缘情况。虽然'Length'被公开为属性,但您不能在任何前面提出的解决方案中使用它。

using Contract = System.Diagnostics.Contracts.Contract;
using Exprs = System.Linq.Expressions;


static string PropertyNameFromMemberExpr(Exprs.MemberExpression expr)
{
return expr.Member.Name;
}


static string PropertyNameFromUnaryExpr(Exprs.UnaryExpression expr)
{
if (expr.NodeType == Exprs.ExpressionType.ArrayLength)
return "Length";


var mem_expr = expr.Operand as Exprs.MemberExpression;


return PropertyNameFromMemberExpr(mem_expr);
}


static string PropertyNameFromLambdaExpr(Exprs.LambdaExpression expr)
{
if (expr.Body is Exprs.MemberExpression)   return PropertyNameFromMemberExpr(expr.Body as Exprs.MemberExpression);
else if (expr.Body is Exprs.UnaryExpression)    return PropertyNameFromUnaryExpr(expr.Body as Exprs.UnaryExpression);


throw new NotSupportedException();
}


public static string PropertyNameFromExpr<TProp>(Exprs.Expression<Func<TProp>> expr)
{
Contract.Requires<ArgumentNullException>(expr != null);
Contract.Requires<ArgumentException>(expr.Body is Exprs.MemberExpression || expr.Body is Exprs.UnaryExpression);


return PropertyNameFromLambdaExpr(expr);
}


public static string PropertyNameFromExpr<T, TProp>(Exprs.Expression<Func<T, TProp>> expr)
{
Contract.Requires<ArgumentNullException>(expr != null);
Contract.Requires<ArgumentException>(expr.Body is Exprs.MemberExpression || expr.Body is Exprs.UnaryExpression);


return PropertyNameFromLambdaExpr(expr);
}

现在看用法示例:

int[] someArray = new int[1];
Console.WriteLine(PropertyNameFromExpr( () => someArray.Length ));

如果PropertyNameFromUnaryExpr没有检查ArrayLength,“someArray”将被打印到控制台(编译器似乎生成了对支持长度的直接访问,作为优化,即使在调试中,因此是特殊情况)。

public string GetName<TSource, TField>(Expression<Func<TSource, TField>> Field)
{
return (Field.Body as MemberExpression ?? ((UnaryExpression)Field.Body).Operand as MemberExpression).Member.Name;
}

这个函数处理成员表达式和一元表达式。区别在于,如果表达式表示值类型,则得到UnaryExpression;如果表达式表示引用类型,则得到MemberExpression。所有内容都可以转换为对象,但值类型必须被装箱。这就是UnaryExpression存在的原因。# EYZ2

出于可读性考虑(@Jowen),这里有一个扩展的等效内容:

public string GetName<TSource, TField>(Expression<Func<TSource, TField>> Field)
{
if (object.Equals(Field, null))
{
throw new NullReferenceException("Field is required");
}


MemberExpression expr = null;


if (Field.Body is MemberExpression)
{
expr = (MemberExpression)Field.Body;
}
else if (Field.Body is UnaryExpression)
{
expr = (MemberExpression)((UnaryExpression)Field.Body).Operand;
}
else
{
const string Format = "Expression '{0}' not supported.";
string message = string.Format(Format, Field);


throw new ArgumentException(message, "Field");
}


return expr.Member.Name;
}

我发现一些向下钻取到MemberExpression/UnaryExpression建议答案不捕获嵌套/子属性。

o => o.Thing1.Thing2返回Thing1而不是Thing1.Thing2

如果您正在尝试使用EntityFramework DbSet.Include(...),那么这种区别非常重要。

我发现,只解析Expression.ToString()似乎就可以了,而且速度相对较快。我将它与UnaryExpression版本进行了比较,甚至从Member/UnaryExpression中获得了ToString版本,以查看是否更快,但差异可以忽略不计。如果这是个糟糕的主意,请纠正我。

可拓法

/// <summary>
/// Given an expression, extract the listed property name; similar to reflection but with familiar LINQ+lambdas.  Technique @via https://stackoverflow.com/a/16647343/1037948
/// </summary>
/// <remarks>Cheats and uses the tostring output -- Should consult performance differences</remarks>
/// <typeparam name="TModel">the model type to extract property names</typeparam>
/// <typeparam name="TValue">the value type of the expected property</typeparam>
/// <param name="propertySelector">expression that just selects a model property to be turned into a string</param>
/// <param name="delimiter">Expression toString delimiter to split from lambda param</param>
/// <param name="endTrim">Sometimes the Expression toString contains a method call, something like "Convert(x)", so we need to strip the closing part from the end</param>
/// <returns>indicated property name</returns>
public static string GetPropertyName<TModel, TValue>(this Expression<Func<TModel, TValue>> propertySelector, char delimiter = '.', char endTrim = ')') {


var asString = propertySelector.ToString(); // gives you: "o => o.Whatever"
var firstDelim = asString.IndexOf(delimiter); // make sure there is a beginning property indicator; the "." in "o.Whatever" -- this may not be necessary?


return firstDelim < 0
? asString
: asString.Substring(firstDelim+1).TrimEnd(endTrim);
}//--   fn  GetPropertyNameExtended

(检查分隔符甚至可能是多余的)

演示(LinqPad)

演示+比较代码——https://gist.github.com/zaus/6992590

这是一个通用的实现,用于获取struct/class/interface/delegate/array的字段/属性/索引器/方法/扩展方法/委托的字符串名称。我已经测试了静态/实例和非泛型/泛型变体的组合。

//involves recursion
public static string GetMemberName(this LambdaExpression memberSelector)
{
Func<Expression, string> nameSelector = null;  //recursive func
nameSelector = e => //or move the entire thing to a separate recursive method
{
switch (e.NodeType)
{
case ExpressionType.Parameter:
return ((ParameterExpression)e).Name;
case ExpressionType.MemberAccess:
return ((MemberExpression)e).Member.Name;
case ExpressionType.Call:
return ((MethodCallExpression)e).Method.Name;
case ExpressionType.Convert:
case ExpressionType.ConvertChecked:
return nameSelector(((UnaryExpression)e).Operand);
case ExpressionType.Invoke:
return nameSelector(((InvocationExpression)e).Expression);
case ExpressionType.ArrayLength:
return "Length";
default:
throw new Exception("not a proper member selector");
}
};


return nameSelector(memberSelector.Body);
}

这个东西也可以写在一个简单的while循环中:

//iteration based
public static string GetMemberName(this LambdaExpression memberSelector)
{
var currentExpression = memberSelector.Body;


while (true)
{
switch (currentExpression.NodeType)
{
case ExpressionType.Parameter:
return ((ParameterExpression)currentExpression).Name;
case ExpressionType.MemberAccess:
return ((MemberExpression)currentExpression).Member.Name;
case ExpressionType.Call:
return ((MethodCallExpression)currentExpression).Method.Name;
case ExpressionType.Convert:
case ExpressionType.ConvertChecked:
currentExpression = ((UnaryExpression)currentExpression).Operand;
break;
case ExpressionType.Invoke:
currentExpression = ((InvocationExpression)currentExpression).Expression;
break;
case ExpressionType.ArrayLength:
return "Length";
default:
throw new Exception("not a proper member selector");
}
}
}

我喜欢递归方法,尽管第二种方法可能更容易阅读。我们可以这样称呼它:

someExpr = x => x.Property.ExtensionMethod()[0]; //or
someExpr = x => Static.Method().Field; //or
someExpr = x => VoidMethod(); //or
someExpr = () => localVariable; //or
someExpr = x => x; //or
someExpr = x => (Type)x; //or
someExpr = () => Array[0].Delegate(null); //etc


string name = someExpr.GetMemberName();

打印最后一个成员。

注意:

  1. 对于像A.B.C这样的链式表达式,将返回“C”。

  2. 这并不适用于# eyz0,数组索引器或# eyz1(不可能涵盖所有情况)。

这是对卡梅伦方法的更新。第一个参数不是必需的。

public PropertyInfo GetPropertyInfo<TSource, TProperty>(
Expression<Func<TSource, TProperty>> propertyLambda)
{
Type type = typeof(TSource);


MemberExpression member = propertyLambda.Body as MemberExpression;
if (member == null)
throw new ArgumentException(string.Format(
"Expression '{0}' refers to a method, not a property.",
propertyLambda.ToString()));


PropertyInfo propInfo = member.Member as PropertyInfo;
if (propInfo == null)
throw new ArgumentException(string.Format(
"Expression '{0}' refers to a field, not a property.",
propertyLambda.ToString()));


if (type != propInfo.ReflectedType &&
!type.IsSubclassOf(propInfo.ReflectedType))
throw new ArgumentException(string.Format(
"Expresion '{0}' refers to a property that is not from type {1}.",
propertyLambda.ToString(),
type));


return propInfo;
}

您可以执行以下操作:

var propertyInfo = GetPropertyInfo<SomeType>(u => u.UserID);
var propertyInfo = GetPropertyInfo((SomeType u) => u.UserID);

扩展方法:

public static PropertyInfo GetPropertyInfo<TSource, TProperty>(this TSource source,
Expression<Func<TSource, TProperty>> propertyLambda) where TSource : class
{
return GetPropertyInfo(propertyLambda);
}


public static string NameOfProperty<TSource, TProperty>(this TSource source,
Expression<Func<TSource, TProperty>> propertyLambda) where TSource : class
{
PropertyInfo prodInfo = GetPropertyInfo(propertyLambda);
return prodInfo.Name;
}

您可以:

SomeType someInstance = null;
string propName = someInstance.NameOfProperty(i => i.Length);
PropertyInfo propInfo = someInstance.GetPropertyInfo(i => i.Length);

这是另一个答案:

public static string GetPropertyName<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression)
{
var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);


return metaData.PropertyName;
}

现在在c# 6中,你可以简单地使用nameof,就像这个nameof(User.UserId)

这有很多好处,其中之一是在编译时完成,而不是运行时。

https://msdn.microsoft.com/en-us/magazine/dn802602.aspx

我正在为c# 6之前的项目使用扩展方法,为那些针对c# 6的项目使用nameof ()

public static class MiscExtentions
{
public static string NameOf<TModel, TProperty>(this object @object, Expression<Func<TModel, TProperty>> propertyExpression)
{
var expression = propertyExpression.Body as MemberExpression;
if (expression == null)
{
throw new ArgumentException("Expression is not a property.");
}


return expression.Member.Name;
}
}

我称之为:

public class MyClass
{
public int Property1 { get; set; }
public string Property2 { get; set; }
public int[] Property3 { get; set; }
public Subclass Property4 { get; set; }
public Subclass[] Property5 { get; set; }
}


public class Subclass
{
public int PropertyA { get; set; }
public string PropertyB { get; set; }
}


// result is Property1
this.NameOf((MyClass o) => o.Property1);
// result is Property2
this.NameOf((MyClass o) => o.Property2);
// result is Property3
this.NameOf((MyClass o) => o.Property3);
// result is Property4
this.NameOf((MyClass o) => o.Property4);
// result is PropertyB
this.NameOf((MyClass o) => o.Property4.PropertyB);
// result is Property5
this.NameOf((MyClass o) => o.Property5);

它可以很好地处理字段和属性。

下面是另一种获得基于这个答案。的PropertyInfo的方法,它消除了对对象实例的需要。

/// <summary>
/// Get metadata of property referenced by expression. Type constrained.
/// </summary>
public static PropertyInfo GetPropertyInfo<TSource, TProperty>(Expression<Func<TSource, TProperty>> propertyLambda)
{
return GetPropertyInfo((LambdaExpression) propertyLambda);
}


/// <summary>
/// Get metadata of property referenced by expression.
/// </summary>
public static PropertyInfo GetPropertyInfo(LambdaExpression propertyLambda)
{
// https://stackoverflow.com/questions/671968/retrieving-property-name-from-lambda-expression
MemberExpression member = propertyLambda.Body as MemberExpression;
if (member == null)
throw new ArgumentException(string.Format(
"Expression '{0}' refers to a method, not a property.",
propertyLambda.ToString()));


PropertyInfo propInfo = member.Member as PropertyInfo;
if (propInfo == null)
throw new ArgumentException(string.Format(
"Expression '{0}' refers to a field, not a property.",
propertyLambda.ToString()));


if(propertyLambda.Parameters.Count() == 0)
throw new ArgumentException(String.Format(
"Expression '{0}' does not have any parameters. A property expression needs to have at least 1 parameter.",
propertyLambda.ToString()));


var type = propertyLambda.Parameters[0].Type;
if (type != propInfo.ReflectedType &&
!type.IsSubclassOf(propInfo.ReflectedType))
throw new ArgumentException(String.Format(
"Expression '{0}' refers to a property that is not from type {1}.",
propertyLambda.ToString(),
type));
return propInfo;
}

它可以这样调用:

var propertyInfo = GetPropertyInfo((User u) => u.UserID);

我已经更新了@Cameron的回答,包括一些安全检查Convert类型的lambda表达式:

PropertyInfo GetPropertyName<TSource, TProperty>(
Expression<Func<TSource, TProperty>> propertyLambda)
{
var body = propertyLambda.Body;
if (!(body is MemberExpression member)
&& !(body is UnaryExpression unary
&& (member = unary.Operand as MemberExpression) != null))
throw new ArgumentException($"Expression '{propertyLambda}' " +
"does not refer to a property.");


if (!(member.Member is PropertyInfo propInfo))
throw new ArgumentException($"Expression '{propertyLambda}' " +
"refers to a field, not a property.");


var type = typeof(TSource);
if (!propInfo.DeclaringType.GetTypeInfo().IsAssignableFrom(type.GetTypeInfo()))
throw new ArgumentException($"Expresion '{propertyLambda}' " +
"refers to a property that is not from type '{type}'.");


return propInfo;
}

如果你想要获得多个字段,我就保留这个函数:

/// <summary>
/// Get properties separated by , (Ex: to invoke 'd => new { d.FirstName, d.LastName }')
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="exp"></param>
/// <returns></returns>
public static string GetFields<T>(Expression<Func<T, object>> exp)
{
MemberExpression body = exp.Body as MemberExpression;
var fields = new List<string>();
if (body == null)
{
NewExpression ubody = exp.Body as NewExpression;
if (ubody != null)
foreach (var arg in ubody.Arguments)
{
fields.Add((arg as MemberExpression).Member.Name);
}
}


return string.Join(",", fields);
}

从。net 4.0开始,你可以使用ExpressionVisitor来查找属性:

class ExprVisitor : ExpressionVisitor {
public bool IsFound { get; private set; }
public string MemberName { get; private set; }
public Type MemberType { get; private set; }
protected override Expression VisitMember(MemberExpression node) {
if (!IsFound && node.Member.MemberType == MemberTypes.Property) {
IsFound = true;
MemberName = node.Member.Name;
MemberType = node.Type;
}
return base.VisitMember(node);
}
}

下面是如何使用这个访问者:

var visitor = new ExprVisitor();
visitor.Visit(expr);
if (visitor.IsFound) {
Console.WriteLine("First property in the expression tree: Name={0}, Type={1}", visitor.MemberName, visitor.MemberType.FullName);
} else {
Console.WriteLine("No properties found.");
}

使用c# 7模式匹配:

public static string GetMemberName<T>(this Expression<T> expression)
{
switch (expression.Body)
{
case MemberExpression m:
return m.Member.Name;
case UnaryExpression u when u.Operand is MemberExpression m:
return m.Member.Name;
default:
throw new NotImplementedException(expression.GetType().ToString());
}
}

例子:

public static RouteValueDictionary GetInfo<T>(this HtmlHelper html,
Expression<Func<T, object>> action) where T : class
{
var name = action.GetMemberName();
return GetInfo(html, name);
}

[更新]c# 8模式匹配:

public static string GetMemberName<T>(this Expression<T> expression) => expression.Body switch
{
MemberExpression m => m.Member.Name,
UnaryExpression u when u.Operand is MemberExpression m => m.Member.Name,
_ => throw new NotImplementedException(expression.GetType().ToString())
};
static void Main(string[] args)
{
var prop = GetPropertyInfo<MyDto>(_ => _.MyProperty);


MyDto dto = new MyDto();
dto.MyProperty = 666;


var value = prop.GetValue(dto);
// value == 666
}


class MyDto
{
public int MyProperty { get; set; }
}


public static PropertyInfo GetPropertyInfo<TSource>(Expression<Func<TSource, object>> propertyLambda)
{
Type type = typeof(TSource);


var member = propertyLambda.Body as MemberExpression;
if (member == null)
{
var unary = propertyLambda.Body as UnaryExpression;
if (unary != null)
{
member = unary.Operand as MemberExpression;
}
}
if (member == null)
{
throw new ArgumentException(string.Format("Expression '{0}' refers to a method, not a property.",
propertyLambda.ToString()));
}


var propInfo = member.Member as PropertyInfo;
if (propInfo == null)
{
throw new ArgumentException(string.Format("Expression '{0}' refers to a field, not a property.",
propertyLambda.ToString()));
}


if (type != propInfo.ReflectedType && !type.IsSubclassOf(propInfo.ReflectedType))
{
throw new ArgumentException(string.Format("Expression '{0}' refers to a property that is not from type {1}.",
propertyLambda.ToString(), type));
}


return propInfo;
}

这可能是最优的

public static string GetPropertyName<TResult>(Expression<Func<TResult>> expr)
{
var memberAccess = expr.Body as MemberExpression;
var propertyInfo = memberAccess?.Member as PropertyInfo;
var propertyName = propertyInfo?.Name;


return propertyName;
}

GetPropetyAccess ()是可用的,如果你可以参考efcore。

using Microsoft.EntityFrameworkCore.Infrastructure;


var propertyInfo = lambda.GetPropetyAccess(); //PropertyInfo
var propertyName = propertyInfo.Name;

假设(TModel作为类)

Expression<Func<TModel, TValue>> expression

检索属性的名称

expression.GetPropertyInfo().Name;

扩展函数:

public static PropertyInfo GetPropertyInfo<TType, TReturn>(this Expression<Func<TType, TReturn>> property)
{
LambdaExpression lambda = property;
var memberExpression = lambda.Body is UnaryExpression expression
? (MemberExpression)expression.Operand
: (MemberExpression)lambda.Body;


return (PropertyInfo)memberExpression.Member;
}