Ian*_*son 7 c# linq lambda compiled
我已经看到可以将编译的方法一起添加.
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();
Run Code Online (Sandbox Code Playgroud)
这样做有意义吗?
我打算使用过滤器代替lambda表达式来过滤客户的存储库:
IEnumerable<Customer> customersFound = _repo.Customers.Where(filter);
Run Code Online (Sandbox Code Playgroud)
根据业务逻辑,我可能会或可能不会将三个编译的方法一起添加,但是选择,并可能添加更多编译的方法.
任何人都可以解释是否将它们组合在一起会构建查询字符串吗?有人有更好的建议吗?
我可以链接"Where"语句并使用常规的lambda表达式,但我对你可能从编译方法中获得的内容感兴趣并添加它们!
这是Compile方法返回委托这一事实的副作用.
在内部,委托是多播委托,它可以涉及对方法的多个链式引用.
该+是在这种情况下,只是为了把它们连在一起的快捷方式.您可以在如何:在MSDN上组合代理中阅读有关组合代理的更多信息.
这是一个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; }
Run Code Online (Sandbox Code Playgroud)
输出:
X()
Y()
Z()
3
Run Code Online (Sandbox Code Playgroud)
请注意,它似乎只是忽略第一个方法调用的返回值,并且只返回最后一个,尽管它也完全调用了先前的方法.
请注意,上面的代码与此类似:
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; }
Run Code Online (Sandbox Code Playgroud)
简而言之就是不,这不符合你的意愿.
当您调用时Compile(),您正在创建类型的实例Func<Customer, bool>,这是一个委托.
委托重载operator+以返回多播代理,这是这里发生的事情.
请参阅MSDN: How to: Combine Delegates (Multicast Delegates)
所以,不 - 将它们加在一起不会构建查询字符串.
如果这是EF,你想使用表达式树,而不是Lambdas.
您可以使用System.Linq.Expressions命名空间创建和修改表达式树:
MSDN: System.Linq.Expressions Namespace
和
MSDN: How to: Use Expression Trees to Build Dynamic Queries
链接谓词是一种创造性的努力,但遗憾的是它不起作用。Lasse 和 Nicholas (+2) 很好地解释了原因。但你也会问:
有人有更好的建议吗?
编译表达式的缺点是它们不再是表达式,因此不能与IQueryableSQL 查询提供程序(例如 linq to sql 或 linq toEntity)支持的 s 一起使用。我认为_repo.Customers是这样的IQueryable。
如果您想动态链接表达式,LINQKit 的PredicateBuilder 是执行此操作的绝佳工具。
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());
Run Code Online (Sandbox Code Playgroud)
这就是它的用途Expand:
实体框架的查询处理管道无法处理调用表达式,这就是您需要对查询中的第一个对象调用 AsExpandable 的原因。通过调用 AsExpandable,您可以激活 LINQKit 的表达式访问者类,该类用实体框架可以理解的更简单的构造替换调用表达式。
或者:如果没有它,表达式为Invoked,这会导致 EF 中出现异常:
LINQ to Entities 不支持 LINQ 表达式节点类型“Invoke”。
顺便提一句。如果您使用 linq to sql/entities,您也可以使用c.lastname == _customer.lastName,因为它会被转换为 SQL,并且数据库排序规则将决定大小写敏感度。
| 归档时间: |
|
| 查看次数: |
234 次 |
| 最近记录: |