Are lambda expressions supported by Razor?

2019-03-14 19:20发布

问题:

Are lambda expressions/anonymous methods supported in the Razor view engine?

I am having difficulty expressing the following in Razor:

@Model.ToList().ForEach(i =>
    {
        if (i.DealerName != null) 
        {
            <text> 
                @i.DealerName
            </text>
        }
    }

Note: I know can solve this with @foreach but I need a similar solution for a 3rd party MVC control. It using this mechanism for setting the content of the control. It works fine for MVC .ASPX views but cannot get it to work with Razor.


MVC .ASPX equivalent (the code I would like to convert to Razor syntax):

<% Model.ToList().ForEach(i =>
       {
           if (i.DealerName != null)
           { 
           %> <%=i.DealerName%> <%
           };
       }); 
%>

This is for the Razor engine that ships with ASP.NET MVC3.

回答1:

Instead of your <text>@i.DealerName</text> block you could use a Response.Write(i.DealerName);

The result is the same, as if you drop this in a Razor page - it will execute while rendering page.. And frankly - I'm pretty sure this is what it will be compiled into anyway.

Also, since ForEach() returns void, you'd have to drop it in the page as a code block. So your code would look something like this:

@{
    Model.ToList().ForEach(i =>
    {
        if (i.DealerName != null) 
        {
            Response.Write(i.DealerName);
        }
    });
}

UPD: If you have more serious formatting, you can resort to this nice little trick:
(unfortunately the code colouring here will not give this snippet any credit, but you'll definitely see what I mean if you drop this in visual studio. Note: this will only work in Razor pages, not code files :) )

@{
    Model.ToList().ForEach(i =>
    {
        if (i.DealerName != null) 
        {
            Response.Write(((Func<dynamic, object>)(
                @<text>
                    <b>Hello Dealer named: @item.DealerName
                    Multiline support is <em>Beautiful!</em>
                </text>)).Invoke(i));
        }
    });
}

Hope that makes sense :)



回答2:

Alternatively, you can create a lambda function, and call that for each item in the body of your Razor code (the idea came from Andy in this post):

@model IEnumerable<Dealer>

@{
    Func<Dealer, object> sayHi = 
        @<text>
             <b>Hello Dealer named: @(item.DealerName)</b>
             Multiline support is <em>Beautiful!</em>
         </text>;
}

<div>
    @foreach(var dealer in Model.ToList())
    {
        sayHi(dealer);
    }
</div>


回答3:

Yes, they are supported. BUT, Razor has some weird escaping rules and extra braces will cause it to choke sometimes, including those in extended lambda expressions.

You can simplify the @Artioms answer a bit to remove those extra braces with a where and optionally a select clause

@{
    Model.ToList().ForEach(i =>
    {
        if (i.DealerName != null) 
        {
            Response.Write(i.DealerName);
        }
    });
}

becomes

@{
    Model.Where(i=>i.DealerName != null).ToList().ForEach(i =>
    {
            Response.Write(i.DealerName);
    });
}

Could also become

@{Model.Where(i=>i.DealerName != null).Select(i=>i.DealerName)
    .ToList().ForEach(Response.Write);}

Yay functional styles!