7

我已经看到可以将编译的方法一起添加。

Expression<Func<Customer, bool>> ln = c => c.lastname.Equals(_customer.lastName, StringComparison.InvariantCultureIgnoreCase);
Expression<Func<Customer, bool>> fn = c => c.firstname.Equals(_customer.firstName, StringComparison.InvariantCultureIgnoreCase);
Expression<Func<Customer, bool>> fdob = c => c.DOB.ToString("yyyyMMdd").Equals(_customer.DOB.ToString("yyyyMMdd"));

var filter = ln.Compile() + fn.Compile() + fdob.Compile();

这样做有意义吗?

我打算使用过滤器代替 lambda 表达式来过滤客户存储库:

IEnumerable<Customer> customersFound = _repo.Customers.Where(filter);

根据业务逻辑,我可能会也可能不会将三个编译方法添加在一起,但会选择并可能会添加更多编译方法。

谁能解释将它们加在一起是否会建立一个查询字符串?有人有更好的建议吗?

我可以链接“Where”语句并使用常规 lambda 表达式,但我对编译方法并将它们相加可能获得的东西很感兴趣!

4

3 回答 3

7

这是Compile方法返回委托这一事实的副作用。

在内部,委托是一个多播委托,它可以涉及对方法的多个链接引用。

在这种+情况下,这只是将它们链接在一起的一种快速方法。您可以在 MSDN 上的How to: Combine Delegates中阅读有关组合委托的更多信息。

这是一个演示的LINQPad程序:

void Main()
{
    var filter = GetX() + GetY() + GetZ();
    filter().Dump();
}

public int X() { Debug.WriteLine("X()"); return 1; }
public int Y() { Debug.WriteLine("Y()"); return 2; }
public int Z() { Debug.WriteLine("Z()"); return 3; }

public Func<int> GetX() { return X; }
public Func<int> GetY() { return Y; }
public Func<int> GetZ() { return Z; }

输出:

X()
Y()
Z()
3

请注意,它似乎只是忽略了第一个方法调用的返回值,只返回最后一个,尽管它也完全调用了先前的方法。

请注意,上面的代码与此类似:

void Main()
{
    Func<int> x = X;
    Func<int> y = Y;
    Func<int> z = Z;

    var filter = x + y + z;
    filter().Dump();
}

public int X() { Debug.WriteLine("X()"); return 1; }
public int Y() { Debug.WriteLine("Y()"); return 2; }
public int Z() { Debug.WriteLine("Z()"); return 3; }

因此,简短的回答是不,这不会做你想做的事。

于 2013-03-30T18:47:25.810 回答
5

当您调用 时Compile(),您正在创建类型的实例Func<Customer, bool>,它是一个委托。

代表重载operator+返回多播代表,这就是这里发生的事情。

见 MSDN:How to: Combine Delegates (Multicast Delegates)

所以,不 - 将它们加在一起不会建立查询字符串。


如果这是用于 EF,您想使用表达式树,而不是 Lambda。

您可以使用命名空间创建和修改表达式树System.Linq.Expressions

MSDN:System.Linq.Expressions Namespace

MSDN:How to: Use Expression Trees to Build Dynamic Queries

于 2013-03-30T18:48:14.537 回答
3

链接谓词是一种创造性的努力,可惜它不起作用。Lasse 和 Nicholas (+2) 很好地解释了原因。但你也问:

有人有更好的建议吗?

编译表达式的缺点是它们不再是表达式,因此不能与IQueryable受 SQL 查询提供程序(如 linq to sql 或 linq to entity)支持的 s 一起使用。我假设_repo.Customers是这样的IQueryable

If you want to chain expressions dynamically, LINQKit's PredicateBuilder is an excellent tool to do this.

var pred = Predicate.True<Customer>();

pred = pred.And(c => c.lastname.Equals(_customer.lastName, StringComparison.InvariantCultureIgnoreCase);
pred = pred.And(c => c.firstname.Equals(_customer.firstName, StringComparison.InvariantCultureIgnoreCase);
pred = pred.And(c => c.DOB.ToString("yyyyMMdd").Equals(_customer.DOB.ToString("yyyyMMdd"));

var customersFound = _repo.Customers.Where(pred.Expand());

This is what the Expand is for:

Entity Framework's query processing pipeline cannot handle invocation expressions, which is why you need to call AsExpandable on the first object in the query. By calling AsExpandable, you activate LINQKit's expression visitor class which substitutes invocation expressions with simpler constructs that Entity Framework can understand.

Or: without it an expression is Invoked, which causes an exception in EF:

The LINQ expression node type 'Invoke' is not supported in LINQ to Entities.

BTW. If you use linq to sql/entities you may as well use c.lastname == _customer.lastName because it is translated into SQL and the database collation will determine case sensitiveness.

于 2013-03-30T20:17:27.740 回答