简体   繁体   English

LINQ如何动态使用多个ThenBy?

[英]LINQ How to use multiple ThenBy dynamically?

I didn't think this would be so rare to find but as it seems, it is. 我不认为这会很难找到,但看起来似乎是这样。 Here's the situation. 这是情况。

I've a ApplySort method which takes in 3 parameters posted from a mvc page. 我有一个ApplySort方法,它接受从mvc页面发布的3个参数。

    private List<dynamic> ApplySort(List<dynamic> listToBeSorted, string sortBy, string sortOrder)
    {
        if (String.IsNullOrEmpty(sortBy))
            sortBy = "createddate";
        if (String.IsNullOrEmpty(sortOrder) || sortOrder.Trim() != "0")
            sortOrder = "1"; // 1 = descending, 0 = ascending
        if (sortOrder == "1")
        {
            switch (sortBy)
            {
                case "name":
                    listToBeSorted = listToBeSorted.OrderByDescending(a => a.name).ToList();
                    break;
                case "assigned":
                    listToBeSorted = listToBeSorted.OrderByDescending(a => a.title).ToList();
                    break;
                case "duedate":
                    listToBeSorted = listToBeSorted.OrderByDescending(a => a.end).ToList();
                    break;
                case "status":
                    listToBeSorted = listToBeSorted.OrderByDescending(a => a.title).ToList();
                    break;
                default:
                    listToBeSorted = listToBeSorted.OrderByDescending(a => a.title).ToList();
                    break;
            }
        }
        else
        {
            // same code as in if-block, with just OrderBy calls instead of OrderByDescending
        }
        return listToBeSorted;
    }

Two problems: 两个问题:

1) Method seems unnecessarily long (with very similar code inside if and else blocks). 1)方法似乎不必要很长(if和else块内部的代码非常相似)。

2) I want to be able to sort using multiple columns. 2) 我希望能够使用多列进行排序。 sortBy param can have values like "name,title,createddate,status". sortBy param可以包含“name,title,createddate,status”之类的值。 So the sort applied should be, first by name, thenby title, then by createddate...and so on. 因此,应用的排序应首先按名称,然后按标题,然后按创建日期...依此类推。 I can use ThenBy by checking params sequentially. 我可以通过顺序检查params来使用ThenBy But how to dynamically apply a chain of ThenBy (s) based on the param value, where the number of ThenBy can vary . 但是如何基于param值动态应用ThenBy链 ,其中ThenBy的数量可以变化

string[] sortParams = sortBy.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
listToBeSorted.OrderBy(i=>i.sortParams[0]).ThenBy(j=>j.sortParams[1]).ThenBy(k=>k.sortParams[2])...(so on till sortParams.length)

How would I do this ? 我该怎么做? Plus, also how can I use the sortOrder parameter to sort by ascending or descending in the same line instead of using if-else. 另外,我如何使用sortOrder参数在同一行中升序或降序排序,而不是使用if-else。

You can create dictionary with Func<string, IComparable> mapping to properties of your class. 您可以使用Func<string, IComparable>映射到类的属性来创建字典。

public class ItemWithProperty
{
    public string Property { get; set; }
}

public static void Main()
{
    Dictionary<string, Func<ItemWithProperty, IComparable>> stringPropertyMap = new Dictionary<string, Func<ItemWithProperty, IComparable>>()
    {
       {"param1", item => item.Property}
    };

    List<ItemWithProperty> toBeOrdered = new List<ItemWithProperty>();

    string[] parameters = {"param1"};
    var sorted = toBeOrdered.OrderBy(stringPropertyMap[parameters[0]]);
}

You use this if you change your method signature: 如果更改方法签名,则使用此方法:

    private static IEnumerable<dynamic> ApplySort(IEnumerable<dynamic> listToBeSorted, ICollection<KeyValuePair<string, string>> sorters)
    {
        var orderBy = (sorters == null || sorters.Count == 0) ? new KeyValuePair<string, string>("createddate", "1") : sorters.First();
        var thenBys = (sorters == null || sorters.Count == 1) ? new List<KeyValuePair<string, string>>() : sorters.Except(Enumerable.Repeat(orderBy, 1));

        var orderedEnumerable = orderBy.Value == "1"
            ? listToBeSorted.OrderBy(x => GetPropertyValue(x, orderBy.Key))
            : listToBeSorted.OrderByDescending(x => GetPropertyValue(x, orderBy.Key));

        orderedEnumerable = thenBys.Aggregate(orderedEnumerable, (current, thenBy) => thenBy.Value == "1"
            ? current.ThenBy(x => GetPropertyValue(x, thenBy.Key))
            : current.ThenByDescending(x => GetPropertyValue(x, thenBy.Key)));

        return orderedEnumerable.ToList();
    }

    private static object GetPropertyValue(dynamic obj, string propName)
    {
        Type t = obj.GetType();
        return t.GetProperty(propName).GetValue(obj, null);
    }

Try : 试试:

    static void Main(string[] args)
    {
        var list = new List<dynamic>();
        list.Add(new { name = "Billy" });
        list.Add(new { name = "Johnny" });
        list.Add(new { name = "Ali" });

        var list2 = ApplySort(list, new List<KeyValuePair<string, string>>(new List<KeyValuePair<string, string>> { new KeyValuePair<string, string>("name", "1") }));

        foreach (var o in list2)
        {
            Console.WriteLine(o.name);
        }

        Console.ReadLine();

    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM