从 lambda 表达式中获取一个 属性 名称 *没有* 对象实例

Get a property name from a lambda expression *without* an object instance

Asp.net MVC 在 Html 泛型 class 上引入了 EditorFor 方法。它允许您编写简洁地标识视图模型字段的代码。在这种情况下,此代码的来源页面必须具有某种类型的视图模型,该视图模型具有 StudentId 属性 否则这将不起作用。

@Html.EditorFor(m => m.StudentId)

EditorFor属性的签名是这样的。

EditorFor<TModel,TValue>(HtmlHelper<TModel>, Expression<Func<TModel,TValue>>)

该方法是在知道 TModel 类型的通用类型上定义的。所以 lambda 表达式可以像 m => m.StudentId 一样简单,我们都知道 m 的类型就是 TModel 的类型。在这种情况下,它是页面的视图模型。

我希望能够编写类似的代码,而不知道 属性 定义在什么类型上。我希望能够写...

@Html.EditorFor(M.StudentId) // here M is a type not a lambda parameter
@Html.EditorFor(X.Y) // here X is a type not a lambda parameter

我希望能够指定任意类型和任意参数,并使用可识别两者的内容调用该方法。例如,如果使用 PropertyInfo 调用该方法,那么我可以同时看到 属性 和定义它的类型。

换句话说...就像 nameof(X.Y) 为任意类型 X 给出字符串 "Y" 一样,我想要一个表达式,它给出类似PropertyInfo 也是。也许 property(X.Y) 并且您从类型 X.

中取回 属性 YPropertyInfo

您可以像 EditorFor 一样使用 属性 表达式。您可以在没有实例的情况下执行此操作。

一个区别是您必须指定表达式参数的类型来告诉编译器对象类型是什么。所以而不是

EditorFor( x => x.Name );    //Specifies a property but not a type

...你的表情应该是这样的:

EditorFor( (MyType x) => x.Name ); //Specifies property and the type it belongs to

您可以使用像这样的简短方法来完成此操作:

static PropertyInfo GetPropertyInfo<TIn, TOut>(Expression<Func<TIn, TOut>> expression)
{
    var memberExp = expression.Body as MemberExpression;
    return memberExp?.Member as PropertyInfo;
}

然后你可以这样做:

var p1 = GetPropertyInfo((string s) => s.Length);
Console.WriteLine("{0}.{1}", p1.DeclaringType.FullName, p1.Name);

var p2 = GetPropertyInfo((DateTime d) => d.Minute);
Console.WriteLine("{0}.{1}", p2.DeclaringType.FullName, p2.Name);

var p3 = GetPropertyInfo((Stream s) => s.CanSeek);
Console.WriteLine("{0}.{1}", p3.DeclaringType.FullName, p3.Name);

输出:

System.String.Length
System.DateTime.Minute
System.IO.Stream.CanSeek

请注意,我们从来不需要任何实例。