user1652656
user1652656

Reputation: 53

Using given properties as strings

I would like to use a single, general method to retrieve an ordered list for a given string representing a property inside a lambda expression.

I know people requested this before but it didn't work for me. I tried this and it threw error:

db.Books.OrderByDescending(x => x.GetType().GetProperty("Discount").GetValue(x,null))
        .Take(3);

I'm using this at the moment:

public IQueryable<Book> GetCheapestBooks()
{
    return db.Books.OrderBy(x => x.Discount)
                   .Take(3);
}

Upvotes: 1

Views: 113

Answers (4)

Lee
Lee

Reputation: 144206

You could create an extension method which creates the property expression:

private static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string propertyName)
{
    PropertyInfo prop = typeof(T).GetProperty(propertyName);
    ParameterExpression paramExpr = Expression.Parameter(typeof(T), "obj");
    MemberExpression propExpr = Expression.Property(paramExpr, prop);

    Type funcType = typeof(Func<,>).MakeGenericType(typeof(T), prop.PropertyType);
    Type keySelectorType = typeof(Expression<>).MakeGenericType(funcType);
    LambdaExpression keySelector = Expression.Lambda(funcType, propExpr, paramExpr);

    MethodInfo orderByMethod = typeof(Queryable).GetMethods().Single(m => m.Name == "OrderBy" && m.GetParameters().Length == 2).MakeGenericMethod(typeof(T), prop.PropertyType);
    return (IOrderedQueryable<T>) orderByMethod.Invoke(null, new object[] { source, keySelector });
}

Upvotes: 0

Aghilas Yakoub
Aghilas Yakoub

Reputation: 29000

You can try with this code

public IQueryable<Book> GetCheapestBooks()
{
    db.Books.OrderBy(x => x.Discount).Take(3).AsQueryable<Book>();
}

Upvotes: 0

Dmytro
Dmytro

Reputation: 17196

Simple console application.

class A
        {
            public int prop1 { get; set; }
            public int prop2 { get; set; }
        }

    class Program
    {
        static IEnumerable<T> GenericOrderByDescending<T>(IEnumerable<T> arg, string property, int take)
        {
            return arg.OrderByDescending(x => x.GetType().GetProperty(property).GetValue(x, null)).Take(take);
        }

        static void Main(string[] args)
        {           
            IEnumerable<A> arr = new List<A>()
                                     {
                                         new A(){ prop1 = 1, prop2 = 2},
                                         new A(){prop1 = 2,prop2 =2},
                                         new A(){prop1 = 3,prop2 =2},
                                         new A(){prop1 = 441,prop2 =2},
                                         new A(){prop1 = 2,prop2 =2}
                                     };

            foreach(var a1 in GenericOrderByDescending<A>(arr, "prop1", 3))
            {
                Console.WriteLine(a1.prop1);
            }
        }
    }

U can pass your db.Boks.AsEnumerable() as parameter for GenericOrderByDescending<T>() method. Instead of T you should type the type of your db.Boks items. My example sorts an array of instances of class A and I've got no errors, it works fine. Did I understand you correctly?

Upvotes: 0

Viper
Viper

Reputation: 2236

maybe this is what you are looking for:

Dynamic Linq

With this you can write queries like:

var result = db.Books.OrderBy( "Discount" ).Take( 3 );

Upvotes: 1

Related Questions