修改表达式<func<T,布尔值>>



我没有使用过那么多的表达式,所以我不能说我的意图是否有任何意义。我在网上找了一遍,但是一无所获。

假设我有一个这样的方法

public async Task<T> GetFirstWhereAsync(Expression<Func<T, bool>> expression)
{
    // this would be a call to 3rd party dependency
    return await SomeDataProvider
        .Connection
        .Table<T>()
        .Where(expression)
        .FirstOrDefaultAsync();
}

在my-other-code中,我可以调用它例如

private async Task<User> GetUser(Credentials credentials)
{
    return await SomeDataSource
        .GetFirstWhereAsync(u => u.UserName.Equals(credentials.UserName));
}

所以我将从匹配给定表达式的SomeDataProvider中接收第一个User


我的实际问题是我如何修改GetFirstWhereAsync,使它将一些SecretSauce应用于传递给它的任何表达式?我可以在调用者(s)中这样做,但那将是丑陋的,没有多少乐趣。

如果我传入像

这样的表达式
u => u.UserName.Equals(credentials.UserName);
p => p.productId == 1;

我想把这些修改成

u => u.UserName.Equals(SecretSauce.Apply(credentials.UserName));
p => p.productId == SecrectSauce.Apply(1);

您可以修改方法内部的表达式,但这有点复杂,您需要逐个处理。

下面的例子将处理从x => x.Id == 1x => x.Id == SecretSauce.Apply(1)的修改


class User
{
    public int Id { get; set; }
    public string Name { get; set;}
    public override string ToString()
    {
        return $"{Id}: {Name}"; 
    }
}
<<h3>酱/h3>
class SquareSauce
{
    public static int Apply(int input)
    {
        // square the number
        return input * input;
    }
}

数据
User[] user = new[]
{
    new User{Id = 1, Name = "One"},
    new User{Id = 4, Name = "Four"},
    new User{Id = 9, Name = "Nine"}
};

方法
User GetFirstWhere(Expression<Func<User, bool>> predicate)
{
    //get expression body
    var body = predicate.Body;
    //get if body is logical binary (a == b)
    if (body.NodeType == ExpressionType.Equal)
    {
        var b2 = ((BinaryExpression)body);
        var rightOp = b2.Right;
        // Sauce you want to apply
        var methInfo = typeof(SquareSauce).GetMethod("Apply");      
        // Apply sauce to the right operand
        var sauceExpr = Expression.Call(methInfo, rightOp);
        // reconstruct equals expression with right operand replaced 
        // with "sauced" one
        body = Expression.Equal(b2.Left, sauceExpr);
        // reconstruct lambda expression with new body
        predicate = Expression.Lambda<Func<User, bool>>(body, predicate.Parameters);
    }
    /*
        deals with more expression type here using else if
    */
    else
    {
        throw new ArgumentException("predicate invalid");
    }
    return user
        .AsQueryable()
        .Where(predicate)
        .FirstOrDefault();
}
使用

Console.WriteLine(GetFirstWhere(x => x.Id == 2).ToString());

该方法将把x => x.Id == 2变为x => x.Id == SquareSauce.Apply(2),并将产生:

4:

最新更新