创建动态表达式<func <tin,tout =“”>&gt;从一个字符串

时间:2017-09-20 09:32:59

标签: c# linq expression

我正在为REST API构建一个库,以允许动态查询Mongo数据库中的文档。

假设以下Person实体:

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

    public Address Address { get; set; }
}

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

现在,我想创建一个引用动态字段的Expression<Func<TInput, TOutput>>

假设一个方法接受2个字符串,1表示要查询的字段,1表示值,此方法可能如下所示:

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

当使用Name这样的单个属性调用上述方法时,可以相对容易地构建表达式:

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

但是如何构建一个公开嵌入字段的表达式,例如Address.Street

亲切的问候

2 个答案:

答案 0 :(得分:0)

您可以查看ExpressionBuilder项目。它可能会帮助您解决您的问题。在FilterBuilder中,您会找到:

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

Helper Class中的GetMemberExpression确实:

因此它基本上在递归中包装多个PropertyExpressions(因为Expression基本上可以是&#34; Address.Street.Number&#34;等等):

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

答案 1 :(得分:0)

试试这个

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