Currying Expressions in C#

拈花ヽ惹草 提交于 2019-12-01 06:49:09

this example might help you. I guess the best is to build the expression without lambdas:

public class Entity
{
    public Entity(string someField)
    {
        SomeField = someField;
    }

    public string SomeField { get; set;  }
}

class Program
{
    static void Main(string[] args)
    {
        var entities = new[] {new Entity("fooBar"), new Entity("barBaz"), new Entity("baz"), new Entity("foo")};
        entities.Where(BuildExpression("ar","az").Compile())
                .ToList()
                .ForEach(e => Console.WriteLine(e.SomeField));
        Console.ReadLine();
    }

    public static Expression<Func<Entity, bool>> BuildExpression(params string[] words)
    {
        var parameter = Expression.Parameter(typeof (Entity));

        var matchs = words.Select(word =>
                                        {
                                            var property = Expression.Property(parameter, "SomeField");
                                            var toLower = Expression.Call(property, "ToLower", new Type[] {});
                                            var contains = Expression.Call(toLower, "Contains",
                                                                            new Type[]{},
                                                                            Expression.Constant(word));
                                            return contains;
                                        }).OfType<Expression>();

        var body = matchs.Aggregate(Expression.Or);

        return Expression.Lambda<Func<Entity, bool>>(body, new[] {parameter});
    } 
}

Please let me know if I should add more information to this answer.

I like using linq to build epression trees, it makes me feel uber-powerfull, so I've added this, not as a complete answer to your question, but more a an elegant way to build up expression trees...

var query = ...;
var search = "asdfasdf";
var fields = new Expression<Func<MyEntity,string>>[]{ 
    x => x.Prop1, 
    x => x.Prop2, 
    x => x.Prop3 
};
var notFields = new Expression<Func<MyEntity,string>>[]{ 
    x => x.Prop4, 
    x => x.Prop5 };

//----- 
var paramx = Expression.Parameter(query.ElementType);

//get fields to search for true
var whereColumnEqualsx = fields
    .Select(x => Expression.Invoke(x,paramx))
    .Select(x => Expression.Equal(x,Expression.Constant(search)))
    //you could change the above to use .Contains(...) || .StartsWith(...) etc.
    //you could also make it not case sensitive by 
    //wraping 'x' with a .ToLower() expression call, 
    //and setting the search constant to 'search.ToLower()'
    .Aggregate((x,y) => Expression.And(x,y));

//get fields to search for false
var whereColumnNotEqualsx = notFields
    .Select(x => Expression.Invoke(x,paramx))
    .Select(x => Expression.NotEqual(x, Expression.Constant(search)))
    //see above for the different ways to build your 'not' expression,
    //however if you use a .Contains() you need to wrap it in an Expression.Negate(...)
    .Aggregate((x,y) => Expression.Or(x,y));
    //you can change Aggregate to use Expression.And(...) 
    //if you want the query to exclude results only if the 
    //search string is in ALL of the negated fields.

var lambdax = Expression.Lambda(
    Expression.And(whereColumnEqualsx, whereColumnNotEqualsx), paramx);

var wherex = Expression.Call(typeof(Queryable)
    .GetMethods()
    .Where(x => x.Name == "Where")
    .First()
    .MakeGenericMethod(query.ElementType),
    query.Expression,lambdax);

//create query
var query2 = query.Provider.CreateQuery(wherex).OfType<MyEntity>();
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!