C# 什么';将编译后的Func方法添加到一起的目的是什么?
我已经看到,可以将编译后的方法添加到一起C# 什么';将编译后的Func方法添加到一起的目的是什么?,c#,linq,lambda,compiled,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.
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();
Expression ln=c=>c.lastname.Equals(_customer.lastname,StringComparison.InvariantCultureIgnoreCase);
表达式fn=c=>c.firstname.Equals(_customer.firstname,StringComparison.InvariantCultureIgnoreCase);
表达式fdob=c=>c.DOB.ToString(“yyyyMMdd”)。等于(_customer.DOB.ToString(“yyyyMMdd”);
var filter=ln.Compile()+fn.Compile()+fdob.Compile();
这样做有意义吗
我打算使用过滤器代替lambda表达式来过滤客户存储库:
IEnumerable<Customer> customersFound = _repo.Customers.Where(filter);
IEnumerable customersFound=\u repo.Customers.Where(过滤器);
根据业务逻辑的不同,我可能会也可能不会将这三个编译方法添加到一起,但我会选择,并可能会添加更多的编译方法
有人能解释一下,把它们加在一起是否会形成一个查询字符串吗?有人有更好的建议吗
我可以链接“Where”语句并使用正则lambda表达式,但我对您从编译方法和添加方法中获得的好处很感兴趣 这是该方法返回委托这一事实的副作用 在内部,委托是一个多播委托,它可以涉及对方法的多个链接引用 在本例中,
+
只是将它们链接在一起的一种快速方法。您可以在MSDN上的中阅读有关组合代理的更多信息
下面是一个演示以下内容的程序:
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; }
请注意,它似乎只是忽略了第一个方法调用的返回值,只返回最后一个,尽管它也完全调用了前面的方法
请注意,上述代码与此类似:
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; }
void Main()
{
Func x=x;
Func y=y;
Func z=z;
var过滤器=x+y+z;
filter().Dump();
}
public int X(){Debug.WriteLine(“X()”);返回1;}
public int Y(){Debug.WriteLine(“Y()”);返回2;}
public int Z(){Debug.WriteLine(“Z()”);返回3;}
因此,简短的回答是不,这不符合您的要求。当您调用
Compile()
时,您正在创建Func
类型的实例,它是一个委托
委托重载操作符+
,以返回多播委托,这就是此处发生的情况
见MSDN:
因此,否-将它们添加在一起不会生成查询字符串
如果这是针对EF的,那么您希望使用表达式树,而不是lambda 您可以使用
System.Linq.Expressions
命名空间创建和修改表达式树:
MSDN:
及
MSDN:链接谓词是一项创造性的工作,可惜它不起作用。Lasse和Nicholas(+2)很好地解释了原因。但你也会问: 有人有更好的建议吗 编译表达式的缺点是它们不再是表达式,因此不能与SQL查询提供程序(如linq to SQL或linq to entities)支持的
IQueryable
s一起使用。我假设回购客户是这样的一个IQueryable
如果要动态链接表达式,PredicateBuilder是一个很好的工具
var pred=Predicate.True();
pred=pred.And(c=>c.lastname.Equals(_customer.lastname,StringComparison.InvariantCultureIgnoreCase);
pred=pred.And(c=>c.firstname.Equals(_customer.firstname,StringComparison.invariantCultureInogoreCase);
pred=pred.和(c=>c.DOB.ToString(“yyyyymmdd”)。等于(_customer.DOB.ToString(“yyyyymmdd”);
var customersFound=_repo.Customers.Where(pred.Expand());
这就是展开的的作用:
实体框架的查询处理管道无法处理调用表达式,这就是为什么需要对查询中的第一个对象调用AsExpandable。通过调用AsExpandable,可以激活LINQKit的expression visitor类,该类使用实体框架可以理解的更简单的构造替换调用表达式
或者:如果没有它,表达式是Invoke
d,这会导致EF中出现异常:
LINQ to实体中不支持LINQ表达式节点类型“Invoke”
顺便说一句,如果您使用linq to sql/entities,那么您也可以使用c.lastname==\u customer.lastname
,因为它被转换为sql,数据库排序将确定大小写敏感度。谢谢您,Lasse。我看到的证据确实表明,只有链中的最后一个方法被用于过滤,但我不能100%确定其相互关系nals。谢谢你,Nicholas,我会继续关注你的链接。我确实尝试过在谷歌上搜索答案,但我认为我搜索的术语是错误的。非常感谢。@IanDangerRobertson,不客气,谢谢你提出了一个有趣的问题:)谢谢Gert,非常有帮助。我想我会将LinqKit安装到我的项目中并试一试。很遗憾,将代理添加到一起并没有像我希望的那样构建一个过滤器,但LinqKit看起来是一个很好的解决方案,而且在语法上看起来相当干净。我的项目使用EF5和SQL2012,以防有人怀疑。Lasse和Nicholas解释道ned建议将多播代理添加到一起,但Gert建议的解决方案最好回答:“有人有更好的建议吗?”。我已经按照建议使用LinqKit实现了一个解决方案。谢谢;o)
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; }
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());