Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/337.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 什么';将编译后的Func方法添加到一起的目的是什么?_C#_Linq_Lambda_Compiled - Fatal编程技术网

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());