.net Razor中优雅的foreach-else结构

.net Razor中优雅的foreach-else结构,.net,asp.net-mvc,razor,templating,twig,.net,Asp.net Mvc,Razor,Templating,Twig,许多模板引擎都有一种特殊的语法,它是foreach和else的组合。基本上,else子句是在foreach循环没有任何迭代时执行的。如果要在列表回退中显示某种类型的“无”项,则此选项非常有用 例如,在中,可以如下所示 {% for user in users %} <li>{{ user.username|e }}</li> {% else %} <li><em>no user found</em></li>

许多模板引擎都有一种特殊的语法,它是
foreach
else
的组合。基本上,
else
子句是在
foreach
循环没有任何迭代时执行的。如果要在列表回退中显示某种类型的“无”项,则此选项非常有用

例如,在中,可以如下所示

{% for user in users %}
    <li>{{ user.username|e }}</li>
{% else %}
    <li><em>no user found</em></li>
{% endfor %}
{users%]中的用户的%
  • {{user.username | e}}
  • {%else%}
  • 找不到用户
  • {%endfor%}
    使用Razor视图引擎,模板将如下所示,包括对集合中项目数量的额外检查:

    @foreach (var user in users) {
        <li>@user.UserName</li>
    }
    @if (!users.Any()) {
        <li><em>no user found</em></li>
    }
    
    @foreach(用户中的var用户){
    
  • @user.UserName
  • } @如果(!users.Any()){
  • 找不到用户
  • }

    因此,我的问题是:我们能否以某种方式使用Razor View引擎实现类似的优雅。

    我认为实现类似的功能的唯一方法是对
    IEnumerable进行几个扩展:


    这将如何与剃须刀模板适合我仍然不确定。。。。但这可能会给你一些东西继续下去。

    afaik没有内置任何东西,但你可能会扩展它以满足你的需要:


    如果你仍然没有答案,我可能会在以后不使用手机时提供帮助

    整合Jamiec和Martin Booth的答案。我创建了以下扩展方法。它将IEnumerable作为第一个参数,然后使用两个委托来呈现文本。在Razor视图中,我们可以传递模板委托两个参数。简而言之,这意味着您可以提供模板。下面是扩展方法以及如何调用它:

        public static HelperResult Each<TItem>(this IEnumerable<TItem> items, 
            Func<TItem, HelperResult> eachTemplate, 
            Func<dynamic, HelperResult> other)
        {
            return new HelperResult(writer =>
            {
                foreach (var item in items)
                {
                    var result = eachTemplate(item);
                    result.WriteTo(writer);
                }
    
                if (!items.Any())
                {
                    var otherResult = other(new ExpandoObject());
                    // var otherResult = other(default(TItem));
                    otherResult.WriteTo(writer);
                }
            });
        }
    
    然后可以按如下方式调用:

    @(Model.Users
       .Each(@<li>@item.Name</li>)
       .Else(
            @<li>
                <b>No Users</b>
             </li>
            )
    )
    
    @(Model.Users)
    .每个(@
  • @item.Name
  • ) .其他( @
  • 没有用户
  • ) )
    当问题被提出时,这可能是不可能的,但我刚刚做到了这一点:

    @if (Model.EmailAddress.Count() > 0)
    {
        foreach (var emailAddress in Model.EmailAddress)
        {
            <div>@emailAddress.EmailAddress</div>
        }
    } else { <span>No email addresses to display</span>  }
    
    @if(Model.EmailAddress.Count()>0)
    {
    foreach(Model.emailAddress中的var emailAddress)
    {
    @emailAddress.emailAddress
    }
    }else{没有要显示的电子邮件地址}
    
    我认为,如果你将这一点与jamiec的答案结合起来,你就会有一个解决方案!逗号几乎看不见PI同意,但我们没有真正的方法可以绕过这一点,对吗?:)如果为else子句使用命名参数,它可能更具可读性,您可以将其设置为可选。我认为您可以从
    HelperResult
    IHtmlString
    派生,并以类似方式创建
    .else()
    方法。因此,您可以编写:
    @Models.Users.Each(@
  • @item.name
  • )。Else(@
  • 无项
  • 更好的是,从实现ihtmlstring的for-Each扩展方法返回一个自定义类,但这意味着您可以使Else方法仅应用于此自定义类(即不适用于任何ienumerable)
    @Model.Users.Each(
        @<li>@item.Name</li>,
        @<li>
            <b>No Items</b>
         </li>
    )
    
    public static class HtmlHelpers
    {
        public static ElseHelperResult<TItem> Each<TItem>(this IEnumerable<TItem> items, 
            Func<TItem, HelperResult> eachTemplate)
        {
            return ElseHelperResult<TItem>.Create(items, eachTemplate);
        }
    }
    
    public class ElseHelperResult<T> : HelperResult
    {
        private class Data
        {
            public IEnumerable<T> Items { get; set; }
            public Func<T, HelperResult> EachTemplate { get; set; }
            public Func<dynamic, HelperResult> ElseTemplate { get; set; }
    
            public Data(IEnumerable<T> items, Func<T, HelperResult> eachTemplate)
            {
                Items = items;
                EachTemplate = eachTemplate;
            }
    
            public void Render(TextWriter writer)
            {
                foreach (var item in Items)
                {
                    var result = EachTemplate(item);
                    result.WriteTo(writer);
                }
    
                if (!Items.Any() && ElseTemplate != null)
                {
                    var otherResult = ElseTemplate(new ExpandoObject());
                    // var otherResult = other(default(TItem));
                    otherResult.WriteTo(writer);
                }
            }
        }
    
        public ElseHelperResult<T> Else(Func<dynamic, HelperResult> elseTemplate)
        {
            RenderingData.ElseTemplate = elseTemplate;
            return this;
        }
    
        public static ElseHelperResult<T> Create(IEnumerable<T> items, Func<T, HelperResult> eachTemplate)
        {
            var data = new Data(items, eachTemplate);
            return new ElseHelperResult<T>(data);
        }
    
        private ElseHelperResult(Data data)
            : base(data.Render)
        {
            RenderingData = data;
        }
    
        private Data RenderingData { get; set; }
    }
    
    @(Model.Users
       .Each(@<li>@item.Name</li>)
       .Else(
            @<li>
                <b>No Users</b>
             </li>
            )
    )
    
    @if (Model.EmailAddress.Count() > 0)
    {
        foreach (var emailAddress in Model.EmailAddress)
        {
            <div>@emailAddress.EmailAddress</div>
        }
    } else { <span>No email addresses to display</span>  }