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

Posted

技术标签:

【中文标题】从 lambda 表达式中获取属性名称*没有*对象实例【英文标题】:Get a property name from a lambda expression *without* an object instance 【发布时间】:2021-10-08 02:38:41 【问题描述】:

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

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

EditorFor 属性的签名是这样的。

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

该方法是在知道TModel 类型的泛型类型上定义的。所以 lambda 表达式可以像m =&gt; 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

【问题讨论】:

示例代码CallMethodWithProperty(x =&gt; x.Y); 没有证明对对象实例有任何需求...您能否澄清一下您在使用该行时遇到的确切问题(另请查看minimal reproducible example 发布代码指南- 添加额外的var x = new X() 是完全没有必要的......而不是显示CallMethodWithProperty 的定义可以改善问题 - 考虑edit 它) 谢谢我更新了这个问题,以澄清和证明我在问什么。 还是不明白:() =&gt; X.Y 没有意义除非你有一个对象,要么来自封闭范围,要么作为参数传递X =&gt; X.Y 重复? ***.com/questions/671968/… OP,我认为您对 lambda 表达式实际表达的内容感到困惑。在您的第一个示例中,lambda 表达式中的 x 不是您在上面使用 new 关键字创建的实例;它是表达式参数的声明,它成为表达式中的 new 局部变量。该实例未使用。 【参考方案1】:

您可以像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

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

【讨论】:

这正是我想要的。如果语法可以短一点就好了,比如property(X.Y),但是你在这里看到的比使用nameof 更短。谢谢! 从我从@JohnWu 那里学到的东西,我能够在互联网上进行更多的挖掘。我发现这很有帮助。 codeproject.com/articles/1070785/…

以上是关于从 lambda 表达式中获取属性名称*没有*对象实例的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 lambda 表达式和匿名类型获取类型的属性名称?

用于从实体类及其导航属性中选择多个列的 Linq Lambda 表达式

C# 无法从 lambda 表达式中获取类属性值

从 HtmlHelper 的扩展方法中传递的 lambda 表达式中获取属性值的最简单方法是啥?

从 ASP.NET MVC Lambda 表达式中获取价值

从 lambda 函数中检索 cloudformation 堆栈名称