许多模板引擎具有一种特殊的语法,该语法是foreachelse的组合。基本上,else子句在foreach循环没有任何迭代时执行。如果要在列表后备中显示某种类型的无项目,这将很有用。

例如,在Twig中, for loop可以看起来像这样

{% for user in users %}
    <li>{{ user.username|e }}</li>
{% else %}
    <li><em>no user found</em></li>
{% endfor %}

使用Razor View Engine,模板将像这样,涉及对集合中项目数的额外检查:
@foreach (var user in users) {
    <li>@user.UserName</li>
}
@if (!users.Any()) {
    <li><em>no user found</em></li>
}

所以我的问题是:我们可以使用Razor View Engine在某种程度上实现类似的优雅吗?

最佳答案

巩固Jamiec和Martin Booth的答案。我创建了以下扩展方法。它使用IEnumerable作为第一个参数,然后使用两个委托(delegate)来呈现文本。在“ Razor View ”中,我们可以传入模板化委托(delegate)这两个参数。简而言之,这意味着您可以输入模板。因此,这是扩展方法以及如何调用它:

    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);
            }
        });
    }

在 Razor View 中:
@Model.Users.Each(
    @<li>@item.Name</li>,
    @<li>
        <b>No Items</b>
     </li>
)

总而言之,很干净。

更新,以实现注释中提出的建议。此扩展方法使用一个参数来遍历集合中的项目,并返回一个自定义的HelperResult。在该辅助结果上,可以在未找到任何项目的情况下调用Else方法以传递模板委托(delegate)。
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>
        )
)

关于.net - 优雅的foreach-Razor中的else构造,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/7820117/

10-16 22:06