[英]Why do these three pieces of LINQ code produce different (or erroneous) results?
以下是一些示例数据:
List<Book> books = new List<Book>()
{
new Book(){Title = "artemis fowl: the time paradox", Pages = 380},
new Book(){Title = "the lieutenant", Pages = 258},
new Book(){Title = "the wheel of time", Pages = 1032},
new Book(){Title = "ender's game", Pages = 404},
new Book(){Title = "the sphere", Pages = 657}
};
背景:
以上使用Book类的简化版本。 当然,它包含许多领域。 我的最终目标是允许用户执行“高级”搜索,允许用户指定任何字段,并进一步允许用户使用布尔代数为特定字段指定关键字。
例如:在标题搜索文本框中:+(蛋糕|糕点)+〜恶魔
以上意思是:找到标题中有“蛋糕”或“糕点”字样的所有书籍,并且没有“恶魔”这个词。
问题:
宝贝步骤将导致最终的解决方案。 所以我最初有以下代码:
List<Func<Book, bool>> fs = new List<Func<Book, bool>>()
{
b => b.Title.Contains("me"),
b => b.Title.Contains("the")
};
var q2 = from b in books select b;
foreach (var f in fs)
q2 = q2.Where(f);
foreach (Book b in q2)
{
Console.WriteLine("Title:\t\t{0}\nPages:\t\t{1}\n",
b.Title, b.Pages);
}
上面的代码工作正常。 它会在标题中查找包含“和'我'的书籍。
阶段2
现在上面的过滤器类型为Func < Book ,bool>。 该类将是一个实体框架生成的类,我不想在我的UI层中使用,其中将输入搜索短语,并且将生成搜索过滤器以传递给BLL。
所以我有以下三次尝试:
var q = from b in books select b;
List<Func<string, bool>> filters = new List<Func<string, bool>>()
{
s => s.Contains("me"),
s => s.Contains("the"),
};
//This works...
for (int i = 0; i != filters.Count; ++i)
{
Func<string, bool> daF = filters[i];
q = q.Where(b => (daF(b.Title)));
}
//This produces an exception...
//Due to index in query?
// for (int i = 0; i != filters.Count; ++i)
// {
// q = q.Where(b => ((filters[i])(b.Title)));
// }
//This runs but doesn't produce the proper output
// foreach (Func<string, bool> filter in filters)
// q = q.Where(b => filter(b.Title));
foreach (Book b in q)
{
Console.WriteLine("Title:\t\t{0}\nPages:\t\t{1}\n",
b.Title, b.Pages);
}
第一个注释掉的部分触发索引器超出范围异常,表明i的值为2。
第二个评论出来的作品运行并产生输出,但它打印出5本书中的四本......除了标题为“恩德的游戏”的书外。 那是不对的...
所以,阅读我的帖子,我发现我无法记住解释每一个细节的坏习惯......
你去吧 请解释为什么不同的输出。 我想你可能暗示我目前的“解决方案”可能有所改进。
由于我们在这里使用LINQ to Objects,因此您应该能够使用All()
。 那你就不需要循环了。
var query = books.Where(book => filters.All(filter => filter(book.Title)));
这相当于:
var query = from book in books
where filters.All(filter => filter(book.Title))
select book;
至于为什么其他尝试不起作用,你正在关闭循环变量 。 通常,在循环中使用lambda函数时应该小心。 简单的解决方法是声明一个在lambdas中使用的单独变量。 请注意,您实际上是在第一个查询中间接执行此操作。 但是你根本不需要循环,应该使用上面的一个查询。
for (int i = 0; i != filters.Count; ++i)
{
var index = i;
q = q.Where(b => filters[index](b.Title));
}
foreach (Func<string, bool> f in filters)
{
var filter = f;
q = q.Where(b => filter(b.Title));
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.