asp mvc razor 存储 lambda 表达式以列出并重用它

Posted

技术标签:

【中文标题】asp mvc razor 存储 lambda 表达式以列出并重用它【英文标题】:asp mvc razor storing lambda expression to list and reuse it 【发布时间】:2013-01-21 09:28:20 【问题描述】:

我正在使用 asp.mvc 4。假设我有一个名为 Person 的模型,其中包含字段

public class Person

    public int ID  get; set; 
    public string FirstName  get; set; 
    public string SecondName  get; set; 
    public DateTime DateOfBirth  get; set; 
    public DateTime DateOfWorkstart  get; set; 
    public int NumberOfChildren  get; set; 
    public int DepartmentID  get; set; 
    public virtual Department Department  get; set; 


public class Department

    public int ID  get; set; 
    public int NameOfDepartment  get; set; 

在我自动生成的 razor-edit-view 字段中显示如下(为了清楚起见,我只在这篇文章中包含了重要的行)

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

现在我想将 linq-lambda 表达式存储在一个列表中以供以后使用,我不知道该怎么做,我需要这样的东西:

@
    string itemsToShow = "namepart"; // this could also be "otherpart"
    List <Expression<>> list = new List();
    if (itemsToShow.equals("namepart")
    
        list.add(modelItem => item.FirstName);
        list.add(modelItem => item.SecondName);
    
    else
    
        list.add(modelItem => item.DateOfBirth);
        list.add(modelItem => item.DateOfWorkStart);
        list.add(modelItem => item.NumberOfChildren);
    

最后我想像这样使用生成的列表

@foreach (var lambda in list)

    @Html.DisplayFor(lambda)

【问题讨论】:

【参考方案1】:

我会为此编写一个自定义助手:

public static class HtmlExtensions

    public static IHtmlString MyHelper(this HtmlHelper<MyViewModel> html, string itemsToShow)
    
        var sb = new StringBuilder();
        if (itemsToShow == "namepart")
        
            sb.Append(html.DisplayFor(x => x.FirstName));
            sb.Append(html.DisplayFor(x => x.SecondName));
        
        else
        
            sb.Append(html.DisplayFor(x => x.DateOfBirth));
            sb.Append(html.DisplayFor(x => x.DateOfWorkStart));
            sb.Append(html.DisplayFor(x => x.NumberOfChildren));
        
        return new HtmlString(sb.ToString());
    

然后简单地在视图内部:

@Html.MyHelper("namepart")

如果你想渲染另一部分:

@Html.MyHelper("otherpart")

作为替代方案,只需将此内容放入 2 个不同的局部视图中,然后:

@if (itemsToShow == "namepart")

    @Html.Partial("_NamePart", Model)

else

    @Html.Partial("_OtherPart", Model)

【讨论】:

感谢您的建议。是的,这看起来不错,但我的主要目标是了解如何将 lambda 表达式存储到列表中并在以后使用它; 您不能将它存储在列表中,因为您不知道 lambda 表达式的确切类型。您可以使用Expression&lt;Func&lt;MyViewModel, object&gt;&gt;,但如果您尝试将它与模型上的值类型属性(例如 DateTime 或整数)一起使用,这将不适用于 ASP.NET MVC 帮助程序(例如 DisplayFor【参考方案2】:

我的大脑有一点进步。感谢您的建议。正如@darin-dimitrov 所说,秘诀是存储一个表达式树。我更新了我的第一篇文章并添加了一个相关表格。 此示例仅适用于模型已从数据库表中获取“1 单行”(例如在编辑视图中)时;

// first a small helper, which creates the member and checks nullable fields
public static Expression getExpressionPart(ParameterExpression param,
  String s1, String s2)

    Expression member = null;
    if (s2 == null)
    
        member = Expression.Property(param, s1);
    
    else
    
        // the second string is to deal with foreign keys/related data
        member = Expression.PropertyOrField(
          Expression.PropertyOrField(param, s1), s2
        );
    

    Type typeIfNullable = Nullable.GetUnderlyingType(member.Type);
    if (typeIfNullable != null)
    
        member = Expression.Call(member, "GetValueOrDefault", Type.EmptyTypes);
    

现在创建列表和表达式

List<Expression<Func<Person, object>>> list =
  new List<Expression<Func<Person, object>>>();
ParameterExpression param = Expression.Parameter(typeof(Person), "p");

// maps to expression p => p.FirstName
Expression member = getExpressionPart(param, "Firstname", null);
list.Add(Expression.Lambda<Func<Person, object>>(member, param));

// maps to expression p => p.Department.NameOfDepartment
member = getExpressionPart(param, "Department", "NameOfDepartment");
list.Add(Expression.Lambda<Func<Person, object>>(member, param));

现在它可以工作了!

@foreach (var lambda in list)

    @Html.DisplayNameFor(lambda)
    @Html.DisplayFor(lambda)

【讨论】:

【参考方案3】:

您是否尝试过这样存储 lambda:

Func<Person,bool> personExpression = (u => u.FirstName == firstname);

@Html.DisplayFor(personExpression)

对于 2 种输入类型,您的代码将如下所示:

Func<Person,Ticket,bool> personExpression =
        ((u,t) => u.FirstName == firstname && u.SecondName == t.SecondName);

【讨论】:

谢谢,但这不起作用。这会导致编译错误。你用这种方法成功了吗? 是的,它在控制台解决方案中运行良好。我认为 Razor 不支持它,或者?【参考方案4】:

要在剃刀视图中循环遍历模型属性,您应该使用ViewData.ModelMetadata.Properties,如this answer。例如:

@* Loop through properties. *@
@foreach (var property in ViewData.ModelMetadata.Properties)

    @Html.Display(property.PropertyName)

【讨论】:

以上是关于asp mvc razor 存储 lambda 表达式以列出并重用它的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NEt MVC 使用 Web API 返回 Razor 视图

Razor 页面简化了 ASP.NET MVC 应用程序

ASP.NET MVC C# Razor SQL 1 of 2 几乎相同的更新查询不起作用

ASP.NET Core 2,使用没有 MVC 的 Razor 页面单击按钮

MVC-3 ASP.NET 共享视图-重定向-Razor

ASP.NET MVC4 Razor