With the "provided parameters," I can't locate OrderBy on Queryable.

c# expression-trees linq

Question

I want to use the following technique to sort a list:

private static IQueryable<T> BuildQuery<T>(IQueryable<T> query, 
                                           string methodName, 
                                           Expression<Func<T, object>> property)             
    {
        var typeArgs = new[] { query.ElementType, property.Body.Type };

        methodCall = Expression.Call(typeof (Queryable),
                                                  methodName,
                                                  typeArgs,
                                                  query.Expression,
                                                  property);

        return query.Provider.CreateQuery<T>(methodCall);
    }

When I run the code with the following args, I get an exception:

var myPreExistingQuery = new List<SomeType>{ new SomeType() }.AsQueryable();
var query = BuildQuery(myPreExistingQuery, "OrderBy", x => x.SomeProperty);

This is an exception:

No method 'OrderBy' on type 'System.Linq.Queryable' is compatible with the supplied arguments.

Do you know what I'm missing in this situation?

EDIT:

I tried another Expression overload. Call() produced the same exception:

private static IQueryable<T> BuildQuery<T>(IQueryable<T> query, string methodName, Expression<Func<T, object>> propertyExpression)             
    {
        var methodCall = Expression.Call(query.Expression,
                                         methodName,
                                         new[] {query.ElementType, property.Body.Type},
                                         new[] {propertyExpression});

        return query.Provider.CreateQuery<T>(methodCall);
    }
1
8
7/31/2011 10:48:57 PM

Accepted Answer

You must write a new phrase for your property selector if you want it to dynamically perform the necessary calls. The specified selection cannot be used in its present form since it is being typed.Expression<Func<T, object>> and not bringing back your particular kindExpression<Func<T, SomeType>> . By altering the call's type parameters to accept, you may be able to get it to compile.object however since it will be comparing object references, it won't function as intended (and your LINQ provider will may reject it anyway).

You might follow these steps to rebuild your selector expression:

private static IQueryable<T> BuildQuery<T>(
    IQueryable<T> query,
    string methodName,
    Expression<Func<T, object>> property)
{
    var typeArgs = new[] { query.ElementType, property.Body.Type };
    var delegateType = typeof(Func<,>).MakeGenericType(typeArgs);
    var typedProperty = Expression.Lambda(delegateType, property.Body, property.Parameters);

    var methodCall = Expression.Call(
        typeof(Queryable),
        methodName,
        typeArgs,
        query.Expression,
        typedProperty);

    return query.Provider.CreateQuery<T>(methodCall);
}

Making the property type general would be a suitable replacement for this. In this manner, you'll have a selection that is correctly strongly typed right away.

private static IQueryable<TSource> BuildQuery<TSource, TProperty>(
    IQueryable<TSource> query,
    string methodName,
    Expression<Func<TSource, TProperty>> property)
{
    var typeArguments = property.Type.GetGenericArguments();

    var methodCall = Expression.Call(
        typeof(Queryable),
        methodName,
        typeArguments,
        query.Expression,
        property);

    return query.Provider.CreateQuery<TSource>(methodCall);
}
11
8/1/2011 10:10:37 AM


Related Questions





Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow