How do I create a generic Expression that has an expression as a parameter

醉酒当歌 提交于 2019-12-09 01:07:18

问题


There is a DisplayNameFor(x=>x.Title) helper in ASP.Net MVC. I want to implement something similar in behavior.

I want to have a method that accepts an expression based on User class (u=>u.Birthdate or u=>u.Name), a operand (Greater, Less, Equal) and a value like DateTime.Now and returns an expression u=>u.Birthdate > DateTime.Now

I understand that I'll have to build resulting expression manually from pieces. What i can't wrap my head around is passing in and handling of property expression.

Edit:
I want to call a method like
GetFilterPredicate(u=>u.Birthdate,FilterOps.GreaterThan,DateTime.Parse("01.01.2013") or
GetFilterPredicate(u=>u.SomeIntProperty,FilterOps.Equals,2)

Update: I've created a repo with a solution to this question as well as a collection property filtering https://github.com/Alexander-Taran/Lambda-Magic-Filters


回答1:


Does this satisfy your needs ?

[TestClass]
public class UnitTest1
{
    public Expression<Predicate<T>> GetFilterPredicate<T, R>(Expression<Func<T, R>> selector, FilterOps operand, R value)
    {
        var parameter = selector.Parameters[0];

        var left = selector.Body;
        var right = Expression.Constant(value);

        var binaryExpression = Expression.MakeBinary(operand.ToExpressionType(), left, right);
        return Expression.Lambda<Predicate<T>>(binaryExpression, parameter);
    }

    [TestMethod]
    public void TestMethod1()
    {
        var p1 = this.GetFilterPredicate((User u) => u.Birthday.TimeOfDay.Hours, FilterOps.LessThan, 12);
        var p2 = this.GetFilterPredicate((User u) => u.Size, FilterOps.Equal, 180);

        var user = new User() { Birthday = new DateTime(2000, 1, 1), Size = 180 };

        Assert.IsTrue(p1.Compile()(user));
        Assert.IsTrue(p2.Compile()(user));
    }
}

public enum FilterOps
{
    GreaterThan, LessThan, Equal
}
public static class MyExtensions
{
    public static ExpressionType ToExpressionType(this FilterOps operand)
    {
        switch (operand)
        {
            case FilterOps.GreaterThan: return ExpressionType.GreaterThan;
            case FilterOps.LessThan: return ExpressionType.LessThan;
            case FilterOps.Equal: return ExpressionType.Equal;
            default: throw new NotSupportedException();
        }
    }
}

public class User { public DateTime Birthday { get; set; } public int Size { get; set; } }



回答2:


I believe this is what you're aiming for.

public Func<User, bool> MyMethod<TProperty>(Expression<Func<User, TProperty>> func, ComparisonPredicate op, TProperty value)
{


}

public enum ComparisonPredicate
{
    Equal,
    Unequal,
    LessThan,
    LessThanOrEqualTo,
    GreaterThan,
    GreaterThanOrEqualTo
}



回答3:


something like this:

Expression<Func<TObject, TProperty>> GenerateAssignExpression<TObject, TProperty>
    (Expression<Func<TObject, TProperty>> getExpression,
    TProperty Value)
{
    var getExpressionBody = getExpression.Body as MemberExpression;
    if (getExpressionBody == null)
    {
        throw new Exception("getExpressionBody is not MemberExpression: " + 
                getExpression.Body);
    }

    var objectParameter = (ParameterExpression)getExpression.Parameters[0];
    ConstantExpression constant = Expression.Constant(Value, typeof(TProperty));
    var expAssign = Expression.Assign(e.Body, constant);

    return Expression.Lambda<Func<TObject, TProperty>>(expAssign, 
            objectParameter, 
            valueParameter);
}



回答4:


The below method will produce a binary expression that will have a boolean return value

Expression<Predicate<TObject>> 
     GenerateAssignExpression<TObject, TProperty>(
         Expression<Func<TObject, TProperty>> expression,
         ExpressionType op, 
         TProperty Value)
    {   
        return Expression.Lambda<Predicate<TObject>>(
            Expression.MakeBinary(op, expression, Expression.Constant(Value)),
            getExpression.Parameters[0]);
    }

if you wish for a generic return type just change the Predicate<TObject> to Func<TObject,TReturn> (You need to replace both occurrences of `Predicate´



来源:https://stackoverflow.com/questions/19789386/how-do-i-create-a-generic-expression-that-has-an-expression-as-a-parameter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!