2017-09-20 2 views
0

Je suis en train de créer une bibliothèque pour une API REST afin de pouvoir interroger dynamiquement les documents d'une base de données Mongo.Création d'une expression dynamique <Func <TIn, TOut>> à partir d'une chaîne

On suppose l'entité Person suivante:

public class Person 
{ 
    public string Name { get; set; } 

    public Address Address { get; set; } 
} 

public class Address 
{ 
    public string Street { get; set; } 
} 

Maintenant, je veux créer un Expression<Func<TInput, TOutput>> qui fait référence à un champ dynamique.

Supposons une méthode qui accepte 2 chaînes, 1 représentant le champ d'interroger et d'un représentant la valeur, cette méthode pourrait ressembler à:

public Expression<Func<TInput, TOutput>> Create<TInput, TOutput>(string fieldName, string fieldValue) 
{ 
} 

Lorsque la méthode ci-dessus est appelée avec une seule propriété telle que Name , une expression peut être construite relativement facilement:

var parameter = Expression.Parameter(typeof(Person), string.Empty); 
var field = Expression.PropertyOrField(parameter, "Name"); 
var expression = Expression.Lambda<Func<Person, string>>(field, parameter); 

Mais comment puis-je construire une expression qui expose un champ intégré tel que Address.Street?

Sincères salutations

+0

Avez-vous eu l'occasion de regarder OData? –

+0

Vous devriez partager comment vous voudriez utiliser cette API. C'est plus susceptible de vous obtenir une réponse – Dbl

+0

Je pense que [this] (https://stackoverflow.com/a/45745858/5359302) serait utile pour vous. Vous pouvez vérifier comment il récupère la propriété avec plus d'un niveau d'imbrication. –

Répondre

0

Vous pouvez jeter un oeil à ExpressionBuilder projet. Cela pourrait vous aider beaucoup avec vos préoccupations. En FilterBuilder, vous trouverez:

string parentName = memberName.Substring(0, memberName.IndexOf(".")); 
Expression parentMember = helper.GetMemberExpression(param, parentName); 

Et GetMemberExpression en Helper Class fait:

il encapsule essentiellement plusieurs PropertyExpressions dans une récursion (parce que l'expression pourrait essentiellement être "Address.Street.Number", etc.):

public Expression GetMemberExpression(Expression param, string propertyName) 
{ 
    if (propertyName.Contains(".")) 
    { 
     int index = propertyName.IndexOf("."); 
     var subParam = Expression.Property(param, propertyName.Substring(0, index)); 
     return GetMemberExpression(subParam, propertyName.Substring(index + 1)); 
    } 

    return Expression.Property(param, propertyName); 
} 
0

Essayez cette

public static Expression<Func<TEntity, bool>> Predicate<TEntity>(object value, string name, ExpressionType operation = ExpressionType.Equal) 
    { 
     var parameter = Expression.Parameter(typeof(TEntity), "entity"); 

     // Getting the names of the properties 
     var properties = name.Split("."); 

     //Getting the propety 
     var property = Expression.Property(parameter, properties[0]); 
     property = properties.Skip(1).Aggregate(property, Expression.Property); 

     //Create a Constant Expression for the property value setting its type to be of type of the desired property 
     var propertyValue = Expression.Constant(value, property.Type); 

     //Making the comparison 
     var comparison = Expression.MakeBinary(operation, property, propertyValue); 

     //Creating the expression lambdaExpression. 
     var expression = Expression.Lambda<Func<TEntity, bool>>(comparison, parameter); 

     //Converting the lambdaExpression to required Expression Type 
     return expression.Cast<TEntity, bool>(); 
    } 

    public static Expression<Func<TModel, TResult>> Cast<TModel, TResult>(this LambdaExpression expression) 
    { 
     return Expression.Lambda<Func<TModel, TResult>>(Expression.Convert(expression.Body, typeof(TResult)), expression.Parameters); 
    } 


    public static Expression<Func<TEntity, object>> GetExpression<TEntity>(this string order) 
    { 
     var parameter = Expression.Parameter(typeof(TEntity), "entity"); 
     var properties = order.Split("."); 
     var property = properties.Skip(1).Aggregate(Expression.Property(parameter, properties[0]), Expression.Property); 
     var expression = Expression.Lambda(typeof(Func<,>).MakeGenericType(typeof(TEntity), property.Type), property, parameter); 
     return expression.Cast<TEntity, object>(); 
    }