我怎样才能建立一个“;循环“;Razor的助手

本文关键字:一个 循环 Razor 建立 | 更新日期: 2023-09-27 18:16:30

基本上,我想把这个助手添加到Razor中。我尝试过的:

public static class Html
{
    static Dictionary<string[], int> _cycles;
    static Html()
    {
        _cycles = new Dictionary<string[], int>();
    }
    public static string Cycle(this HtmlHelper helper, string[] options)
    {
        if (!_cycles.ContainsKey(options)) _cycles.Add(options, 0);
        int index = _cycles[options];
        _cycles[options] = (options.Length + 1) % options.Length;
        return options[index];
    }

用法:

<tr class="@Html.Cycle(new[]{"even","odd"})">

但它只是对每一排都说"偶数"。。。不知道为什么。我不确定这个类是什么时候实例化的。。。。。是每个请求一次,每个服务器运行一次。。。还是怎样不管我该如何解决这个问题,以便它给出预期的替换?


尝试#2

public static class Html
{
    public static string Cycle(this HtmlHelper helper, params string[] options)
    {
        if(!helper.ViewContext.HttpContext.Items.Contains("cycles"))
            helper.ViewContext.HttpContext.Items["cycles"] = new Dictionary<string[],int>(new ArrayComparer<string>());
        var dict = (Dictionary<string[], int>)helper.ViewContext.HttpContext.Items["cycles"];
        if (!dict.ContainsKey(options)) dict.Add(options, 0);
        int index = dict[options];
        dict[options] = (index + 1) % options.Length;
        return options[index];
    }
}
class ArrayComparer<T> : IEqualityComparer<T[]>
{
    public bool Equals(T[] x, T[] y)
    {
        if (ReferenceEquals(x, y)) return true;
        if (x == null || y == null) return false;
        if (x.Length != y.Length) return false;
        for (int i = 0; i < x.Length; ++i)
            if (!x[i].Equals(y[i])) return false;
        return true;
    }
    public int GetHashCode(T[] obj)
    {
        return obj.Length > 0 ? obj[0].GetHashCode() : 0;
    }
}

这有什么问题吗?

我怎样才能建立一个“;循环“;Razor的助手

之所以失败,是因为您每次都使用一个全新的数组作为字典的键。

我建议添加一个额外的参数作为dictionary键。

而且看在上帝的份上,请使用私人存储区。(而不是static成员,当多个线程击中页面时,它会爆炸。(

Cycle方法的每次调用都会传递一个新的options数组,向字典中添加一个新键。

要解决这一问题和线程问题,可以将字符串本身用作HttpContext:中的键

string key = "Cycle-"+String.Join("|", options);
if (!html.ViewContext.HttpContext.Items.Contains(key))
     html.ViewContext.HttpContext.Items.Add(key, 0);
int index = html.ViewContext.HttpContext.Items[key];
html.ViewContext.HttpContext.Items[key] = (index + 1) % options.Length;
return options[index];

请注意,这将在子动作和部分之间共享循环。

我发现我也可以用@function来完成。。。那么我不需要将名称空间添加到CCD_ 5。

@using MvcApplication4.Helpers @* for ArrayComparer *@
@functions {
    public static string Cycle(params string[] options)
    {
        if (!HttpContext.Current.Items.Contains("Html.Cycle"))
            HttpContext.Current.Items["Html.Cycle"] = new Dictionary<string[], int>(new ArrayComparer<string>());
        var dict = (Dictionary<string[], int>)HttpContext.Current.Items["Html.Cycle"];
        if (!dict.ContainsKey(options)) dict.Add(options, 0);
        int index = dict[options];
        dict[options] = (index + 1) % options.Length;
        return options[index];
    }
}

也可以用@helper来做,但我认为它不会那么干净。