Création d'arbres d'expression linq pour les objets dynamiques

c# dynamic expression-trees lambda linq

Question

J'essaie de construire un arbre d'expression de manière dynamique pour le tri. Le tri se fera au filtre d'action de mon API Web. Donc, le type d'objet sera inconnu jusqu'au moment de l'exécution.

Voici l'aperçu:
Au niveau du filtre d'action:

IEnumerable<object> model = null;
context.Response.TryGetContentValue(out model);
model=model.OrderByExtension(orderByField, orderDirection);
context.Response.Content=new ObjectContent<IEnumerable<object>>(model, new JsonMediaTypeFormatter());

Et la méthode d'extension:

 public static IQueryable<T> OrderByExtension<T>(this IQueryable<T> source, string sortProperty, Sorting.SortingOption sortOrder)
        {
            var type = source.FirstOrDefault().GetType(); //Gets the type of object passed, since typeof(T) is only object at this point
            var property = type.GetProperty(sortProperty);
            var parameter = Expression.Parameter(type, "p");
            var propertyAccess = Expression.MakeMemberAccess(parameter, property);
            var orderByExp = Expression.Lambda(propertyAccess, parameter);
            var typeArguments = new Type[] { typeof(T), property.PropertyType };
            var methodName = sortOrder == Sorting.SortingOption.Asc ? "OrderBy" : "OrderByDescending";
            var resultExp = Expression.Call(typeof(Queryable), methodName, typeArguments, source.Expression, Expression.Quote(orderByExp));

            return source.Provider.CreateQuery<T>(resultExp);
        }

Sur le Expression.Call - j'obtiens l'erreur: Aucune méthode générique 'OrderByDescending' sur le type 'System.Linq.Queryable' n'est compatible avec les arguments de type fournis

Je suppose qu'il y a une incompatibilité entre le type 'objet' et le type réel lorsque la méthode OrderBy est invoquée.

Y a-t-il un moyen de faire en sorte que cela fonctionne?

Merci d'avance. ps: J'ai également essayé de créer une méthode générique pour OrderBy via .MakeGenericMethod - mais sans succès.

Réponse acceptée

Le problème est que vous générez une expression d'une fonction du type sous-jacent réel, pas du type de l'expression source ( object ). Vous devrez ajouter une conversion à votre type dans l'expression générée.

public static IQueryable<object> OrderByExtension(this IQueryable<object> source, string sortProperty, SortOrder sortOrder = SortOrder.Unspecified)
{
    var sourceType = typeof(object);
    var underlyingType = source.First().GetType();
    var propertyType = underlyingType.GetProperty(sortProperty).PropertyType;
    var param = Expression.Parameter(sourceType);
    var body = Expression.Property(
        Expression.Convert(param, underlyingType), sortProperty
    );
    var lambda = Expression.Lambda(body, param);

    var sortMethod = sortOrder == SortOrder.Descending ? "OrderByDescending" : "OrderBy";
    var expr = Expression.Call(typeof(Queryable), sortMethod, new Type[] { sourceType, propertyType },
        source.Expression, lambda
    );
    return source.Provider.CreateQuery<object>(expr);
}



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi