IEnumerable在没有实际被调用的情况下发生过滤

时间:2014-05-07 19:38:32

标签: c# linq

我使用HtmlAgilityPack来解析HTML页面并从选择列表中检索许多选项元素。

GvsaDivisions是一个从POST结果中返回原始html的方法,在问题的上下文中是不敬的

public IEnumerable<SelectListItem> Divisions(string season, string gender, string ageGroup)
{
    var document = new HtmlDocument();
    var html = GvsaDivisions(season);
    document.LoadHtml(html);

    var options = document.DocumentNode.SelectNodes("//select//option").Select(x => new SelectListItem() { Value = x.GetAttributeValue("value", ""), Text = x.NextSibling.InnerText });

    var divisions = options.Where(x => x.Text.Contains(string.Format("{0} {1}", ageGroup, gender)));
    if (ageGroup == "U15/U16")
    {
        ageGroup = "U15/16";
    }
    if (ageGroup == "U17/U19")
    {
        ageGroup = "U17/19";
    }

    return divisions;
}

我观察到的是......一旦options.Where()被执行,分区就会包含一个结果。在ageGroup == "U15/U16"的测试和ageGroup = "U15/16"的分配之后,分区现在包含3个结果(原始1,添加2个新匹配ageGroup新值的标准

有人可以解释这个异常吗?我希望将一个新的Where查询的结果调用到Union的原始结果,但它似乎是自动发生的。虽然结果是我想要的,但我无法解释它是如何发生的(或确定它会继续以这种方式行事)

3 个答案:

答案 0 :(得分:6)

LINQ查询使用延迟执行,这意味着只要枚举结果就会运行它们。

当您更改查询中使用的变量时,实际上您正在更改下次运行查询的结果,这是您下次迭代结果时的结果。

详细了解此herehere

这实际上是按设计进行的,在许多情况下它非常有用,有时也是必要的。但是,如果您需要立即进行评估,可以在查询结束时调用ToList()方法,具体化您查询并为您提供正常的List<T>对象。

答案 1 :(得分:1)

divisions变量包含一个未处理的枚举器,它在节点列表中的每个元素上调用代码x.Text.Contains(string.Format("{0} {1}", ageGroup, gender))。由于在处理该枚举数之前更改了ageGroup,因此它使用该新值而不是旧值。

例如,以下代码输出一行文本&#34; pear&#34;:

List<string> strings = new List<string> { "apple", "orange", "pear", "watermelon" };
string matchString = "orange";

var queryOne = strings.Where(x => x == matchString);
matchString = "pear";

foreach (var item in queryOne)
{
    Console.WriteLine("   " + item);
}

答案 2 :(得分:0)

我正在思考与特拉维斯相同的问题,延迟执行linq。

我不确定这是否可以避免这个问题,但我通常会将结果放入这样的直接收集中。根据我的经验,一旦你把结果推到一个真正定义的集合中,我相信它可能不会延迟执行。

 List<SelectListItem> options = document.DocumentNode.SelectNodes("//select//option").Select(x => new SelectListItem() { Value = x.GetAttributeValue("value", ""), Text = x.NextSibling.InnerText }).Where(x => x.Text.Contains(string.Format("{0} {1}", ageGroup, gender))).ToList<SelectListItem>();