2

在下面的代码中,当我将“dl.DamageCount > 5”直接放在查询中或将“dl.DamageCount > 5”移动到方法或函数然后从查询中调用它时,有什么区别?

似乎当我将其移入方法时,查询无法正常工作。事实上,无论条件评估如何,函数/方法似乎总是返回 true。我正在使用 Linq-to-NHibernate。

 var q = from dl in session.Linq<DamageList>()
            where
            dl.DamageCount > 5
4

1 回答 1

4

The best you can do is capture the predicate in an Expression<>. A method has already been compiled to IL and so isn't able to be picked apart by a Linq provider.

Expression<Func<DamageList, bool>> predicate = item => item.DamageCount > 5;

You can then pass that predicate directly to Where:

var q = session.Linq<DamageList>().Where(predicate);

If you want to dynamically combine two such expressions, you either write the code for both into the one expression, or you capture both in separate expressions. This gets complicated because you need each one to refer to an item being passed in. This is really a different question, already asked: How do I dynamically create an Expression<Func<MyClass, bool>> predicate?

You can write a compound predicate using the && oerator and still capture it in an expression:

Expression<Func<DamageList, bool>> predicate = 
    dl => dl.DamageCount > 5 && dl.Name.Contains(criteria);

You ask about calling methods in such an expression - well, that example does call a method!

It builds a tree of Expression nodes of various types. Included somewhere will be a method call node, which says to call the Contains method of string (assuming Name is a string). So this is an example of a method call instruction embedded in an expression. In order for this to work, the Linq provider has to know what that method does, so it can turn it into the equivalent SQL (as would be the case for a typical ORM system).

So you can embed certain standard method calls in expressions - it requires the Linq provider to know about them. The methods of string are well defined, but not every provider will necessarily be able to deal with all of them.

It wouldn't be impossible for a Linq provider to allow you to add your own extensions that handle extra methods, but I'm not aware of any that support that (obviously if the system is open source, you can add your own).

To summarise - a Linq provider needs a tree of expression nodes that it can analyse to convert into some other language such as SQL, for execution in another context such as inside a remote database. If you write ordinary methods, the C# compiler will compile them into low-level executable IL, not expression nodes. So that is like a dead-end: there's no built-in facility for turning IL back into expression nodes.

于 2010-02-21T11:31:58.113 回答