[C#.NET][LINQ] OrderBy String (By Property Name)

[C#.NET][LINQ] OrderBy String (By Property Name)

Linq 所提供的排序方法,必須要傳入強型別的屬性給 OrderBy,但有時候還是會用到欄位字串排序,比如說點選 GridView 上的 Column 進行排序,它處理起來其實不難,只要將屬性的值拿出來餵給 IEnumerable.OrderBy | IQueryable.OrderBy 就可以了

 

首先準備假資料:(資料真的很假,年齡跟生日不吻合)

{
    public int Id { get; set; }

    public string Name { get; set; }

    public int Age { get; set; }

    public string Email { get; set; }

    public DateTime? Birthday { get; set; }

    public static IEnumerable<Employee> GetAllEmployees()
    {
        var employees = new List<Employee>();
        employees.Add(new Employee() { Id = 1, Age = 49, Name = "yao", Email = "yao@aa.bb", Birthday = new DateTime(1981, 11, 12, 21, 44, 14) });
        employees.Add(new Employee() { Id = 2, Age = 22, Name = "Kobe", Email = "kobe@aa.cc", Birthday = new DateTime(1966, 08, 11, 20, 35, 14) });
        employees.Add(new Employee() { Id = 3, Age = 33, Name = "Jordan", Email = "jordan@aa.bb", Birthday = new DateTime(1971, 01, 12, 02, 33, 14) });
        employees.Add(new Employee() { Id = 4, Age = 61, Name = "Duke", Email = "Duke@aa.cc", Birthday = new DateTime(1981, 02, 02, 17, 25, 14) });
        employees.Add(new Employee() { Id = 5, Age = 26, Name = "Bill", Email = "bill@aa.cc", Birthday = new DateTime(1980, 03, 12, 13, 25, 14) });
        employees.Add(new Employee() { Id = 6, Age = 25, Name = "Elliot", Email = "Elliot@aa.cc", Birthday = new DateTime(1983, 02, 22, 13, 25, 14) });
        employees.Add(new Employee() { Id = 7, Age = 36, Name = "Gabe", Email = "Gabe@aa.cc", Birthday = new DateTime(1940, 12, 22, 09, 25, 14) });
        employees.Add(new Employee() { Id = 8, Age = 19, Name = "George", Email = "George@aa.cc", Birthday = new DateTime(1987, 03, 22, 13, 25, 14) });
        employees.Add(new Employee() { Id = 9, Age = 21, Name = "Ian", Email = "Ian@aa.cc", Birthday = new DateTime(1940, 09, 23, 13, 04, 14) });
        employees.Add(new Employee() { Id = 10, Age = 28, Name = "Kevin", Email = "Kevin@aa.cc", Birthday = new DateTime(1950, 12, 22, 13, 25, 14) });
        return employees;
    }
}

 

取得物件欄位的值程式碼如下:

{
    PropertyInfo propertyInfo = typeof(TSource).GetProperty(propertyName);
    var result = propertyInfo.GetValue(source, null);
    return result;
}

 

調用端,傳入要排序的欄位即可



 

觀察 LINQ 輸出結果,如我所期望,如下圖

image

 

最後把它們變成擴充方法

{
    return orders(sources, propertyName, false);
}

public static IEnumerable<TSource> OrderByDescending<TSource>(this IEnumerable<TSource> sources, string propertyName)
{
    return orders(sources, propertyName, true);
}

private static IEnumerable<TSource> orders<TSource>(IEnumerable<TSource> sources, string propertyName, bool isDescending)
{
    PropertyInfo propertyInfo = typeof(TSource).GetProperty(propertyName);
    if (propertyInfo == null)
    {
        return sources;
    }
    if (isDescending)
    {
        return sources.OrderByDescending(x => propertyInfo.GetValue(x, null));
    }
    else
    {
        return sources.OrderBy(x => propertyInfo.GetValue(x, null));
    }
}

 

 

當然也可以使用 Expression

參考來源:http://stackoverflow.com/questions/307512/how-do-i-apply-orderby-on-an-iqueryable-using-a-string-column-name-within-a-gene

{
    return orders(sources, propertyName, "OrderBy");
}

public static IQueryable<TSource> OrderByDescending<TSource>(this IQueryable<TSource> sources, string propertyName, params object[] values)
{
    return orders(sources, propertyName, "OrderByDescending");
}

private static IQueryable<TSource> orders<TSource>(IQueryable<TSource> sources, string propertyName, string orderExpression)
{
    var type = typeof(TSource);
    var propertyInfo = type.GetProperty(propertyName);
    var parameter = Expression.Parameter(type, "parameter");
    var propertyAccess = Expression.MakeMemberAccess(parameter, propertyInfo);
    var orderByExp = Expression.Lambda(propertyAccess, parameter);
    MethodCallExpression resultExp = Expression.Call(
        typeof(Queryable),
        orderExpression,
        new Type[] { type, propertyInfo.PropertyType },
        sources.Expression, Expression.Quote(orderByExp));
    return sources.Provider.CreateQuery<TSource>(resultExp);
}

 

 

完整程式碼如下:

https://dotblogsamples.codeplex.com/SourceControl/latest#Simple.LinqOrderByString/Simple.LinqOrderByString/Extensions/LinqExtension.cs

 

最後用單元測試測剛剛寫的方法

程式碼如下:

https://dotblogsamples.codeplex.com/SourceControl/latest#Simple.LinqOrderByString/Simple.LinqOrderByString/UnitTest1.cs

 


本文出自:http://www.dotblogs.com.tw/yc421206/archive/2014/11/25/147419.aspx

專案位置:Simple.LinqOrderByString

 

補充:

Nuget Server 上的 System.Linq.Dynamic,就是在處理這一部份,太晚發現這下白寫了

若有謬誤,煩請告知,新手發帖請多包涵


Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET

Image result for microsoft+mvp+logo