使用Expression <func <t,bool>&gt;编写调用与Func <t,bool>相同

时间:2017-05-20 16:56:54

标签: c# linq lambda linq-expressions

考虑一个可以用作多个其他类的成员的类:

class Customer {
    public string FirstName {get;set;}
    public string LastName {get;set;}
}
// Both "Order" and "Profile" have a "Customer" property
class Order {
    public Customer Customer {get;set;}
}
class Profile {
    public Customer Customer {get;set;}
}

我想定义一个方法,为与Customer关联的对象生成检查器。如果我想要一个内存检查器,我这样做:

static Func<T,bool> Check<T>(Func<T,Customer> conv, string first, string last) {
    return obj => conv(obj).FirstName == first && conv(obj).LastName == last;
}

我可以将我的检查器用于内存序列,如下所示:

var matchingOrders = orders
    .Where(Check<Order>(x => x.Customer, "Foo", "Bar"))
    .ToList();
var matchingProfiles = profiles
    .Where(Check<Profile>(x => x.Customer, "Foo", "Bar"))
    .ToList();

现在我想用Expression<Func<T,bool>>

做同样的事情
static Expression<Func<T,bool>> Check<T>(Expression<Func<T,Customer>> conv, string first, string last)

不幸的是,同样的技巧不起作用:

return obj => conv(obj).FirstName == first && conv(obj).LastName == last;

并像这样使用它:

var matchingOrders = dbContext.Orders
    .Where(Check<Order>(x => x.Customer, "Foo", "Bar"))
    .ToList();
var matchingProfiles = dbContext.Profiles
    .Where(Check<Profile>(x => x.Customer, "Foo", "Bar"))
    .ToList();

这会触发错误:

  

CS0119:表达式表示期望variable', where a方法组

我可以用与撰写代理相同的方式编写表达式吗?

1 个答案:

答案 0 :(得分:1)

不幸的是,C#目前没有提供从Expression<Func<...>>个对象组成表达式的方法。你必须使用表达式树,这需要更长的时间:

static Expression<Func<T,bool>> CheckExpr<T>(Expression<Func<T,Customer>> conv, string first, string last) {
    var arg = Expression.Parameter(typeof(T));
    var get = Expression.Invoke(conv, arg);
    return Expression.Lambda<Func<T,bool>>(
        Expression.MakeBinary(
            ExpressionType.AndAlso
        ,   Expression.MakeBinary(
                ExpressionType.Equal
            ,   Expression.Property(get, nameof(Customer.FirstName))
            ,   Expression.Constant(first)
            )
        ,   Expression.MakeBinary(
                ExpressionType.Equal
            ,   Expression.Property(get, nameof(Customer.LastName))
            ,   Expression.Constant(last)
            )
        )
    ,   arg
    );
}