Реализовать сортировку в Nvelocity

У меня есть класс, который имеет около 50 свойств, экземпляры этого класса добавляются в список. Затем этот список добавляется в контекст Velocity. Теперь я хотел бы отсортировать эти данные. Какое поле, по возрастанию или по убыванию, неизвестно до тех пор, пока шаблон не будет проанализирован.

Ресурсы, которые я изучил:

Как лучше использовать GenericTools Velocity в автономном приложении?< /а>

Список сортировки по скорости для каждого

http://velocity.apache.org/tools/devel/generic/

Основываясь на перечисленных здесь ресурсах, я не могу понять, как это решить. Доступен ли GenericTools для Castle's Nvelocity? Если нет, как я могу реализовать такую ​​​​общую сортировку, о которой я прошу здесь?


person jmelhus    schedule 17.02.2014    source источник


Ответы (1)


Мое решение состояло в том, чтобы написать свой собственный класс сортировки и добавить его в качестве контекста в nvelocity. Я передаю поле для сортировки как строку и обращаюсь к нему как к отражению. Я также устанавливаю сортировку по возрастанию или убыванию по строковому значению. Я также передаю имя компаратора и обращаюсь к нему с отражением. Затем я использую метод списка OrderBy или OrderByDescending с выбранным полем и компаратором.

Я нашел части кода здесь: http://zootfroot.blogspot.co.uk/2009/10/dynamic-linq-orderby.html

public class NvelocitySort
{
    public List<MyObject> Sort(List<MyObject> list, string fieldAndMode, string comparerName)
    {
        fieldAndMode = fieldAndMode.Trim();

        // Split the incoming string to get the field name and sort ascending or descending
        string[] split = fieldAndMode.Split(' ');
        // Set default sort mode
        string mode = "asc";
        // If sort mode not specified, this will be the field name
        string field = fieldAndMode;
        // If sort mode added split length shall be 2
        if (split.Length == 2)
        {
            field = split[0];
            if (split[1].ToLower() == "asc" || split[1].ToLower() == "ascending") mode = "asc";
            if (split[1].ToLower() == "desc" || split[1].ToLower() == "descending") mode = "desc";
        }
        // If length is more than 2 or 0, return same list as passed in
        else if (split.Length > 2 || split.Length == 0)
        {
            return list;
        }

        // Get comparer based on comparer name
        IComparer<string> comparer = (IComparer<string>)Activator.CreateInstance(Type.GetType(string.Format("Namespace.{0}", comparerName)));

        // Choose the sort order
        if (mode == "asc")
            return list.OrderBy(item => item.GetReflectedPropertyValue(field), comparer).ToList();
        if (mode == "desc")
            return list.OrderByDescending(item => item.GetReflectedPropertyValue(field), comparer).ToList();

        // If sort order not asc/desc return same list as passed in
        return list;
    }
}

Это метод отражения для извлечения поля.

public static string GetReflectedPropertyValue(this object subject, string field)
{
    object reflectedValue = subject.GetType().GetProperty(field).GetValue(subject, null);
    return reflectedValue != null ? reflectedValue.ToString() : "";
}

Простой пример сравнения:

public class TextComparer : IComparer<string>
{
    public int Compare(string x, string y)
    {
        return string.Compare(x, y);
    }
}

Добавлено в контекст Nvelocity следующим образом:

this.velocityContext.Put("sorter", new NvelocitySort());

Доступ из шаблона Nvelocity выглядит следующим образом:

#foreach($item in $sorter.Sort($listObject, "Name desc", "TextComparer"))  
$item.Name
#end

Надеюсь, это поможет кому-то еще...

EDIT: нашел еще лучший способ сделать это (реализует сортировку по нескольким полям): http://www.codeproject.com/Articles/280952/Multiple-Column-Sorting-by-Field-Names-Using-Linq

person jmelhus    schedule 19.02.2014