LINQ的意外输出何时按Contains(变量)过滤

时间:2017-01-19 04:08:43

标签: c# linq

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{

    class Program
    {
        static void Main(string[] args)
        {
            string s = "g";
            string[] color = { "greena", "browna", "bluea" };
            var query = color.Where(c => c.Contains(s));
            Console.WriteLine(query.Count());
            s = "a";
            query = query.Where(c => c.Contains(s));
            Console.WriteLine(query.Count());
            Console.ReadKey();

        }
    }
}

我认为它的输出应该是关注的,因为query=color.where(c=>c.contains("g"))我认为它应该包含{greena},所以当第二次查询运行query = query.where(c=>c.contains("a");时,它只匹配绿色,所以当计数时1:

1
1

但运行代码后的输出是

1
3

为什么第二次过滤匹配所有元素(即使只有一个包含" g"第二个查询应该只看一个)?

5 个答案:

答案 0 :(得分:11)

您被捕获的变量咬了一下:

var query = color.Where(c => c.Contains(s));

s提升到一个闭包中,并在执行时读取s 的值。在这种情况下,重新分配s之后会发生这种情况。

您最终得到的结果是:

var query = color.Where(c => c.Contains(s)).Where(c => c.Contains(s));

而不是你可能期待的:

var query = color.Where(c => c.Contains("g")).Where(c => c.Contains("a"));

这将产生您期望的结果:

string s = "g";
string[] color = { "greena", "browna", "bluea" };
var query = color.Where(c => c.Contains(s));
Console.WriteLine(query.Count());
var b = "a";
query = query.Where(c => c.Contains(b));
Console.WriteLine(query.Count()); // <-- This is where the entire expression is evaluated

答案 1 :(得分:3)

查询的第一行:

var query = color.Where(c => c.Contains(s));

不将结果放在查询中。它生成一个查询,该查询具有string []颜色的源,其谓词(过滤器)为.Contains(s)。直到执行.Count()才会执行此操作。

这意味着下一次执行query.Contains()它正在处理原始的项目源。所以,虽然你会期待第一个结果:

s = "g";
color.Where(c => c.Contains(s));

返回1为“greena”的计数,然后

s = "a";
query.Where(c => c.Contains(s)); //  Where query now contains only: "greena" and hence return 1 for a count

真正发生的是:

s = "g";
string[] color = { "greena", "browna", "bluea" };
query = color;
Console.WriteLine(query.Where(c => c.Contains(s)).Count());
// Outputs 1 because g appears only in greena

s = "g";
// query still contains the original color list
Console.WriteLine(query.Where(c => c.Contains(s)).Count());   
// Outputs 3 because a appears in all three

为了按照您的预期运行,您必须在第一个查询中强制执行linq:

string s = "g";
string[] color = { "greena", "browna", "bluea" };
var query = color.Where(c => c.Contains(s)).Select(x => x).ToArray();
// Notice the ToArray() -- it forces execution of the linq which returns the results, not the query itself.
Console.WriteLine(query.Count());
s = "a";
var query2 = query.Select(x => x).Where(c => c.Contains(s));
Console.WriteLine(query2.Count());
Console.ReadKey();

答案 2 :(得分:0)

您的颜色拼写不正确。

Greena,browna,bluea都有'a'字样。你的linq表达式按预期工作。

答案 3 :(得分:0)

因为首先你正在寻找字母'g',只有'greena'包含。之后,您更改s = "a"的值,然后运行查询并查找其中包含字母'a'的所有单词,在这种情况下,其中所有单词都有'a',因此您得到1和3作为一个输出。一切都是正确的。你为什么打算获得1和1?

答案 4 :(得分:0)

在第一部分,它说,你查询所有颜色的字母g里面只有1,这就是它输出1的原因:

string s = "g";
string[] color = { "greena", "browna", "bluea" };
var query = color.Where(c => c.Contains(s));

在第二部分,它说,你查询包含字母a里面的所有颜色,你的数组上的每个索引都有一个字母a,所以输出3:

 s = "a";
 query = query.Where(c => c.Contains(s));
 Console.WriteLine(query.Count());