简体   繁体   English

为什么这三个LINQ代码产生不同(或错误)的结果?

[英]Why do these three pieces of LINQ code produce different (or erroneous) results?

Here is some sample data: 以下是一些示例数据:

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}
};  

Background: 背景:

The above uses a simplified version of a Book class. 以上使用Book类的简化版本。 It would, of course, contain many fields. 当然,它包含许多领域。 My end goal is to allow the user to perform an 'advanced' search allowing the user to specify any field and further allow the user to specify keywords using boolean algebra for a particular field. 我的最终目标是允许用户执行“高级”搜索,允许用户指定任何字段,并进一步允许用户使用布尔代数为特定字段指定关键字。

eg: In a title search text box: the + (cake | pastry) + ~demon 例如:在标题搜索文本框中:+(蛋糕|糕点)+〜恶魔

The above would mean: Find all books that, in the title, have the words 'the', either of 'cake' or 'pastry', and does not have the word 'demon'. 以上意思是:找到标题中有“蛋糕”或“糕点”字样的所有书籍,并且没有“恶魔”这个词。

Problem: 问题:

Baby steps will lead to the final solution. 宝贝步骤将导致最终的解决方案。 So I initially had the following code: 所以我最初有以下代码:

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

The above code works fine. 上面的代码工作正常。 It looks for books that contain 'the' AND 'me' in the title. 它会在标题中查找包含“和'我'的书籍。

Phase 2 阶段2

Now the above filter is of type Func< Book , bool>. 现在上面的过滤器类型为Func < Book ,bool>。 That class will be an Entity Framework generated class and I don't want to use in my UI layer where the search phrase will be input and search filters will be generated to be passed on to the BLL. 该类将是一个实体框架生成的类,我不想在我的UI层中使用,其中将输入搜索短语,并且将生成搜索过滤器以传递给BLL。

So I have the following three attempts: 所以我有以下三次尝试:

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

The first commented-out piece fires an indexer out of range exception stating that the value of i is 2. 第一个注释掉的部分触发索引器超出范围异常,表明i的值为2。

The second commented-out piece runs and produces output, but it prints out FOUR of the 5 books... all EXCEPT the book titled "ender's game". 第二个评论出来的作品运行并产生输出,但它打印出5本书中的四本......除了标题为“恩德的游戏”的书外。 That's not right... 那是不对的...

So, reading over my post, I see that I could not reign in my bad habit of explaining every little detail... 所以,阅读我的帖子,我发现我无法记住解释每一个细节的坏习惯......

So there you go. 你去吧 Please explain why the differing outputs. 请解释为什么不同的输出。 And I guess you could hint on likely improvements to my current 'solution'. 我想你可能暗示我目前的“解决方案”可能有所改进。

Since we're using LINQ to Objects here, you should be able to use All() . 由于我们在这里使用LINQ to Objects,因此您应该能够使用All() Then you won't need to loop. 那你就不需要循环了。

var query = books.Where(book => filters.All(filter => filter(book.Title)));

Which is equivalent to: 这相当于:

var query = from book in books
            where filters.All(filter => filter(book.Title))
            select book;

As for why the other attempts doesn't work, you are closing over the loop variable . 至于为什么其他尝试不起作用,你正在关闭循环变量 Generally, you should be careful when using lambda functions in loops due to this. 通常,在循环中使用lambda函数时应该小心。 The simple fix is to declare a separate variable that you use in your lambdas. 简单的解决方法是声明一个在lambdas中使用的单独变量。 Notice that you actually did this indirectly in your first query. 请注意,您实际上是在第一个查询中间接执行此操作。 However you shouldn't need loops at all and should use one of the queries above. 但是你根本不需要循环,应该使用上面的一个查询。

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.

相关问题 为什么完全相同的代码产生不同的结果? - Why does the exact same code produce different results? 为什么GroupBy中的键入和匿名键选择器会产生不同的结果? - Why do typed and anonymous key selectors in GroupBy produce different results? 为什么PasswordDeriveBytes和Rfc2898DeriveBytes产生不同的结果? - Why do PasswordDeriveBytes and Rfc2898DeriveBytes produce different results? Linq表达式和foreach产生不同的结果 - Linq expression and foreach produce different results 是否可以在LINQ中创建三个不同的条件并产生三个不同的结果? - Is it possible to create three different condtions in LINQ with three different results? 为什么这两个linq查询返回不同数量的结果? - Why do these two linq queries return different numbers of results? 为什么 C# 记录在实现隐式转换时会产生不同的 Linq 表达式? - Why do C# Records produce a different Linq Expression when an implicit conversion is implemented? 为什么这个 LinqPad 程序在第二次运行时会产生不同的结果? - Why does this LinqPad program produce different results on the second run? 为什么这个表达式在 C# 和 C++ 中产生不同的结果? - Why does this expression produce different results in C# and C++? 仅使用Linq或Lambda,如何组合这两段代码以返回List <Entity> è? - Using only Linq or Lambda, how do I combine both pieces of code to return List<Entity> e?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM