加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

.net – 优雅的foreach – 在Razor构建

发布时间:2020-12-16 04:36:46 所属栏目:asp.Net 来源:网络整理
导读:很多模板引擎都有一种特殊的语法,它是foreach和else的结合.基本上,当foreach循环没有任何迭代时执行else子句.如果要在列表回退中显示某种没有项目,这可能很有用. 以Twig为例, for loop可以是这样的 {% for user in users %} li{{ user.username|e }}/li{% el
很多模板引擎都有一种特殊的语法,它是foreach和else的结合.基本上,当foreach循环没有任何迭代时执行else子句.如果要在列表回退中显示某种没有项目,这可能很有用.

以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作为第一个参数,然后使用两个委托来呈现文本.在Razor Views中,我们可以向Templated Delegates传递两个这样的参数.简而言之,这意味着您可以提供模板.所以这是扩展方法以及如何调用它:
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>,@<li>
        <b>No Items</b>
     </li>
)

总而言之,非常干净.

更新实施评论中提出的建议.此扩展方法使用一个参数循环集合中的项并返回自定义HelperResult.在那个helperresult上,如果没有找到任何项目,可以调用Else方法传入模板委托.

public static class HtmlHelpers
{
    public static ElseHelperResult<TItem> Each<TItem>(this IEnumerable<TItem> items,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,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>
        )
)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读