2011-07-31 15 views
8

私は、リストをソートするために使用する方法があります:私は、次の引数を使用してコードを実行したときに、私は例外を取得"提供された引数"を使用してQueryByでOrderByを見つけることができません。

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); 
    } 

を:

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

例外は次のとおりです。

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

私はここで何が欠けているのを誰に見せてもらえますか?

EDIT:

は私がExpression.Callの別のオーバーロードを試してみました()と同じ同じ例外が発生しました:

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); 
    } 
+0

私に 'myPreExistingQuery'の構築を教えてください。 – Femaref

+0

メソッド呼び出しの上に追加しました。 –

答えて

11

あなたがあなたの財産セレクタ式を動的に適切な呼び出しを作りたいので、新しい式を作成する必要があります。指定されたセレクタは、現時点ではExpression<Func<T, object>>と入力されており、特定のタイプExpression<Func<T, SomeType>>が返されないため、そのまま使用することはできません。受理objectを受け入れるために呼び出しの型引数を変更することによってコンパイルすることができるかもしれませんが、オブジェクト参照の比較を行っているので期待どおりに動作しません(LINQプロバイダはそれをとにかく拒否することがあります)。

があなたのセレクタ式を再作成するには、あなたがこれを行うことができます:

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); 
} 

すぎプロパティの型がジェネリックにするだろうこれを行うに素敵な代替。そうすれば、最初から適切に型付けされたセレクタを得ることができます。

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); 
} 
+0

それはまさにITだった。あなたが言ったのは完璧な意味合いです。あなたのコードに貼り付けられ、テストが始まりました。あなたの素晴らしい答えに感謝します。 –

+0

式を再作成する別の方法を追加しました。厳密には、ソースを汎用的にする必要はありません。両方のタイプを汎用にすることができます。 –

+0

あなたの選択肢は他の人には良いことであり、機能をより柔軟にすることは間違いありません。しかし、残念ながら、私は実行時まで型を知らないので、プロパティ型を汎用にすることはできません。 –

関連する問題