使用 Expression<Func<T,bool>> 以与 Func<T,bool> 相同的方式组合调用
Composing invocations with Expression<Func<T,bool>> the same way as Func<T,bool>
考虑一个 class 可以用作多个其他 class 的成员:
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: Expression denotes a variable', where a
method group' was expected
我可以像编写委托一样编写表达式吗?
遗憾的是,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
);
}
考虑一个 class 可以用作多个其他 class 的成员:
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: Expression denotes a
variable', where a
method group' was expected
我可以像编写委托一样编写表达式吗?
遗憾的是,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
);
}