Dynamically Sorting with LINQ

后端 未结 9 2020
自闭症患者
自闭症患者 2020-12-16 04:57

I have a collection of CLR objects. The class definition for the object has three properties: FirstName, LastName, BirthDate.

I have a string that reflects the name

9条回答
  •  执笔经年
    2020-12-16 05:49

    Okay, my argument with SLaks in his comments has compelled me to come up with an answer :)

    I'm assuming that you only need to support LINQ to Objects. Here's some code which needs significant amounts of validation adding, but does work:

    // We want the overload which doesn't take an EqualityComparer.
    private static MethodInfo OrderByMethod = typeof(Enumerable)
        .GetMethods(BindingFlags.Public | BindingFlags.Static)
        .Where(method => method.Name == "OrderBy" 
               && method.GetParameters().Length == 2)
        .Single();
    
    public static IOrderedEnumerable OrderByProperty(
        this IEnumerable source,
        string propertyName) 
    {
        // TODO: Lots of validation :)
        PropertyInfo property = typeof(TSource).GetProperty(propertyName);
        MethodInfo getter = property.GetGetMethod();
        Type propType = property.PropertyType;
        Type funcType = typeof(Func<,>).MakeGenericType(typeof(TSource), propType);
        Delegate func = Delegate.CreateDelegate(funcType, getter);
        MethodInfo constructedMethod = OrderByMethod.MakeGenericMethod(
            typeof(TSource), propType);
        return (IOrderedEnumerable) constructedMethod.Invoke(null,
            new object[] { source, func });
    }
    

    Test code:

    string[] foo = new string[] { "Jon", "Holly", "Tom", "William", "Robin" };
    
    foreach (string x in foo.OrderByProperty("Length"))
    {
        Console.WriteLine(x);
    }
    

    Output:

    Jon
    Tom
    Holly
    Robin
    William
    

    It even returns an IOrderedEnumerable so you can chain ThenBy clauses on as normal :)

提交回复
热议问题