我想了解 @Html.DisplayFor(modelItem => item.FirstName) 中的 lambda 表达式

Posted

技术标签:

【中文标题】我想了解 @Html.DisplayFor(modelItem => item.FirstName) 中的 lambda 表达式【英文标题】:I want to understand the lambda expression in @Html.DisplayFor(modelItem => item.FirstName) 【发布时间】:2012-04-23 06:56:22 【问题描述】:

我是 C# 和 MVC 的新手,在某些场合使用过 lambda,例如匿名方法和 LINQ。

通常我看到的 lambda 表达式看起来像这样:

(x => x.Name), (x =>  Console.WriteLine(x))

我了解 lambda = "goes to"。我从未见过不使用 left 参数的 lambda 表达式。

我不知道如何翻译这个 lambda 表达式

@html.DisplayFor(modelItem => item.FirstName)

谁能帮我解释一下这个?这不应该是

(modelItem => modelItem.FirstName)?

我是从 Microsoft 的 Introduction to ASP.NET MVC tutorial 那里得到的。

【问题讨论】:

你测试过那个实现了吗?它有效吗?以这种方式使用点符号会很好,我的印象是它只能通过索引访问。 是的,这是我在教程中看到的,并且我自己已经做了一段时间了。不过,我一直想知道,为什么不 modelItem => modelItem.FirstName... 也尝试过,但没有奏效。是的,使用点表示法会好得多。在某种程度上,这对我来说似乎是一个“黑客”。我希望将来可以使用点符号.. 根据GraemeMiller的链接,更合适的方式是@Html.DisplayFor( () => item.FirstName) 是的,我同意。相反,它不会那么令人困惑。 【参考方案1】:

lambda 表达式是一种编写匿名函数的方法,即没有名称的函数。 “箭头”左侧是函数参数,右侧是函数体。因此,(x => x.Name) 在逻辑上转换为类似于 string Function(Data x) return x.Name 的类型,stringData 显然会有所不同,并从上下文中派生出来。

左侧参数的缺失转换为没有参数的函数,因此这个(() => someVariable)逻辑上转换为:string Function() return someVariable;

此时你可能会开始疑惑,someVariable 是从哪里来的,它不是函数参数,也没有在函数中定义。你是对的,这样的函数永远不会编译。然而,像这样的 lambda 函数非常好,因为它允许以这种方式提升和使用外部范围变量。 (在内部创建了一个包装类,其中 lambda 表达式中使用的变量成为字段。)

现在让我们看看model => item.FirstName 是什么意思。从逻辑上讲,它将转换为string Function(Model model) return item.FirstName; 。基本上这是一个带参数的函数,但是没有用到这个参数。

现在,最后一点信息。尽管 lambda 表达式最终代表函数,但有时创建它们的目的并不是为了实际执行(尽管它们可能可以)。 lambda 表达式可以用表达式树的形式表示。这意味着它可以被解析,而不是执行它。

在这种特殊情况下,MVC 引擎不会运行 lambda 表达式表示的函数。相反,表达式被 解析 以便 MVC 引擎知道要为该特定行发出什么 html。如果您的数据项不是直接来自模型对象,则 lambda 表达式的左侧部分无关紧要。

【讨论】:

很好的解释。对于这个写得很好的答案,我的答案当然不应该被选中:) @GraemeMiller 是的,我认为这个人的辛勤工作值得称赞和尊重。谢谢。绝对是关于 lambda、MVC 引擎和一般无参数 lambda 的一个非常漂亮的答案:) @zespri 非常感谢您的回答。绝对是一个彻底的答案,并回答了我对 lambdas 和 mvc 引擎的无意识好奇:) "但是像这样的 lamda 函数非常好,因为它允许以这种方式提升和使用外部范围的变量。(在内部创建包装类,其中 lambda 表达式中使用的变量成为字段)”特别有用。有点类似于 javascript 中的闭包。感谢您的出色回答。 很好的答案,但是当你说“这样的函数永远不会编译”时,我认为你是不正确的> 【参考方案2】:

我认为这与 foreach 循环有关。示例:

@foreach(var item in model) 
 
 <td> 
     @html.displayfor(model => item.firstName) </td>
 </td>     

需要使用var item,因为序列中的每一项都是匿名类型。 model =&gt; item.firstName 表示 (input parameter) =&gt; expression。您不能使用输入参数,因为我们将当前“项目”存储在 item 中。

【讨论】:

谢谢!在阅读了主要答案(美丽但非常抽象)之后,这有助于以更实用的方式为我的新手大脑澄清它:-)【参考方案3】:

它使用了一个无参数的lambada。看到这个question

基本上 DisplayFor 不使用 lambda 函数参数模型(它可以是我所说的使用 _ 或 () 的任何东西),而只是在 for 循环中使用 lambda 函数来针对它使用 displayfor。 DisplayFor 需要一个 lambda 函数。

【讨论】:

【参考方案4】:

我也费了很大劲才理解 Visual Studio 生成的代码。我不想提供关于 lambda 表达式的一般解释,而是想使用 ASP.NET MVC 框架放置一个上下文。

假设我们准备了一个具有 2 个属性的模型类(例如 Destination):City 和 ProvinceCode。

public class Destination

    public string City  get; set; 
    public string ProvinceCode  get; set; 

生成Controller和View后,我们应该如前所述通过Visual Studio获取生成的代码。然而,生成的代码有点难以理解,尤其是对于数据行

@Html.DisplayFor(modelItem => item.City)

我只是猜测 MVC 团队应该认为 Html 助手类应该在 cshtml 文件中一致使用。因此,他们尝试使用技巧来通过 C# 编译器。在这种情况下,modelItem 甚至没有用作这个 lambda 表达式的输入参数。我们不能使用 (),因为类型 正确。这就是为什么如果我们替换 model 或任何模型对象,lambda 表达式就可以工作。

说实话,我想以更易读的形式重写生成的代码。除了使用 Html 辅助类,我们可以简单地呈现正确的输出,如下所示:

@foreach (var item in Model) 
<tr>        
    <td>  
        @* Code Generated by Visual Studio. modelItem is a dummy param *@
        @Html.DisplayFor(modelItem => item.City)
    </td>
    <td>
        @* A better way - simply get rid of Html helper class *@
        @item.ProvinceCode
    </td>
</tr>

【讨论】:

是的,如果可以选择排除 DisplayFor,那就太好了。我还希望有排除换行符的选项,这样当有很多单元格时它可以生成紧凑的代码,比如... @item.ProvinceCode

以上是关于我想了解 @Html.DisplayFor(modelItem => item.FirstName) 中的 lambda 表达式的主要内容,如果未能解决你的问题,请参考以下文章

Html.DisplayFor 编译错误 - MVC 2

@Html.DisplayFor 的 MVC6 替代品

MVC3 Html.DisplayFor -- 是不是可以让这个控件生成一个 ID?

在 MVC5 中使用 Html.DisplayFor() 的日期格式

SQL Server 数据库集,配置集 - 但来自数据库的数据未使用 @Html.DisplayFor<>() 显示?

为啥我的 DisplayFor 没有循环通过我的 IEnumerable<DateTime>?