首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >LINQ结果在for循环结束时发生变化

LINQ结果在for循环结束时发生变化
EN

Stack Overflow用户
提问于 2014-03-20 18:30:46
回答 3查看 149关注 0票数 4

当对数据源执行一组LINQ查询(我使用LINQ,但这里也使用List<string>对象)时,我在检查结束时得到了不同的结果。

具体来说,下面的代码试图找出一个完全限定的域名(FQDN)是否存在于主机名列表中(并不是所有这些名称都是FQDN或相同的域,但主机标识符才是我关心的问题)。搜索试图查找列表中是否存在"host-6.domain.local"或其任何子组件(即,"host-6.domain""host-6"),而它们并不存在。在for -循环中,我们得到了我们期望的结果,但是,在for循环完成后,我得到了一个包含列表所有内容的结果,在我看来,这似乎是在试图找到与空字符串匹配的元素。

代码语言:javascript
复制
void MyMethod()  
{  
    string fqdn = "host-6.domain.local";  
    string[] splitFqdn = fqdn.Split('.');  
    List<string> values = new List<string>();  
    values.add("host-1");  
    values.add("host-2.domain.local");  
    values.add("host-3.domain.local");  
    values.add("host-4");  
    values.add("host-5.other.local");  
    IEnumerable<string> queryResult = null;  
    for (int i = splitFqdn.Length; i > 0; i--)  
    {  
        result =  
            from value in values  
            where value.StartsWith(  
                string.Join(".", splitFqdn.Take(i)))  
            select value;  
        Console.WriteLine(  
            "Inside for loop, take " + i + ": "  + result.Count());  
    }  
    Console.WriteLine();  
    Console.WriteLine(  
        "Outside for loop: " + result.Count());  
}

为什么会发生这种情况,如何获得在for循环完成后仍然可以访问的准确结果?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-03-20 18:44:02

你被LINQ懒惰的执行和关闭咬死了。

当您创建一个像您在这里所做的可枚举的.

代码语言:javascript
复制
result =  
    from value in values  
    where value.StartsWith(  
        string.Join(".", splitFqdn.Take(i)))  
    select value;  

它不会被评估直到你做了一些强制它被评估的事情.例如,当您执行result.count()

然后,在循环之外,当您再次计算它时,result.count()将使用您的for循环中存在的i的最后一个值进行计算,这没有给出您想要的结果。

尝试通过对可枚举的.ToList()执行这样的强制求值。此代码显示这两个值,以便进行比较。

代码语言:javascript
复制
void MyMethod()  
{  
    string fqdn = "host-6.domain.local";  
    string[] splitFqdn = fqdn.Split('.');  
    List<string> values = new List<string>();  
    values.add("host-1");  
    values.add("host-2.domain.local");  
    values.add("host-3.domain.local");  
    values.add("host-4");  
    values.add("host-5.other.local");  
    IEnumerable<string> queryResult = null;
    List<string> correctResult = null;
    for (int i = splitFqdn.Length; i > 0; i--)  
    {  
        queryResult =  
            from value in values  
            where value.StartsWith(  
                string.Join(".", splitFqdn.Take(i)))  
            select value;
        correctResult = queryResult.ToList();
        Console.WriteLine(  
            "Inside for loop, take " + i + ": "  + queryResult.Count());  
    }  
    Console.WriteLine();  
    Console.WriteLine(  
        "Outside for loop queryResult: " + queryResult.Count());  
    Console.WriteLine(  
        "Outside for loop correctResult: " + correctResult.Count());  
}

编辑:谢谢指出我没有完全回答这个问题.对于转换为方法语法表示歉意,但是将其转换为查询语法需要更长的时间。

代码语言:javascript
复制
void MyMethod()  
{
    string fqdn = "host-6.domain.local";
    string[] splitFqdn = fqdn.Split('.');
    List<string> values = new List<string>();
    values.Add("host-1");
    values.Add("host-2.domain.local");
    values.Add("host-3.domain.local");
    values.Add("host-4");
    values.Add("host-5.other.local");
    values.Add("host-5.other.local");
    IEnumerable<string> queryResult = null;
    List<string> correctResult = new List<string>();
    for (int i = splitFqdn.Length; i > 0; i--)
    {
        correctResult = correctResult
            .Union(values.Where(
                value => value.StartsWith(string.Join(".", splitFqdn.Take(i)))))
            .ToList();
    }
}
票数 4
EN

Stack Overflow用户

发布于 2014-03-20 19:53:55

对于我的问题,我真的很喜欢凯文的answer,但我不太喜欢在结果上调用.ToList(),因为这将导致从数据库中提取所有匹配的对象(消耗更多内存),而不是执行一个查询,该查询只获得匹配对象的计数(这会稍微快一些,并且不会占用内存来存储对象),因此,使用他的帖子中的信息,我有了这个额外的解决方案,它不需要从数据库中提取所有对象,只运行一个计数查询(在SQL意义上)。

为了避免捕获i (在for -循环结束时成为0 )引起的问题,我只需设置一个临时变量来保存正在搜索的值。

代码语言:javascript
复制
void MyMethod()  
{  
    string fqdn = "host-6.domain.local";  
    string[] splitFqdn = fqdn.Split('.');  
    List<string> values = new List<string>();  
    values.add("host-1");  
    values.add("host-2.domain.local");  
    values.add("host-3.domain.local");  
    values.add("host-4");  
    values.add("host-5.other.local");  
    IEnumerable<string> queryResult = null;  
    for (int i = splitFqdn.Length; i > 0; i--)  
    {  
        //taking the line referencing i out of the 
        //query expression prevents referencing i
        //after it is set to 0 outside the for loop
        string temp = string.Join(".", splitFqdn.Take(i));
        //since temp isn't changed anywhere else, it won't
        //get set to an invalid value after the loop exits
        result =  
            from value in values  
            where value.StartsWith(temp)  
            select value;  
        Console.WriteLine(  
            "Inside for loop, take " + i + ": "  + result.Count());  
    }  
    Console.WriteLine();  
    Console.WriteLine(  
        "Outside for loop: " + result.Count());  
}
票数 2
EN

Stack Overflow用户

发布于 2014-03-20 18:35:49

我认为在为结果变量赋值时需要调用ToList,如下所示:

代码语言:javascript
复制
result =  
            (from value in values  
            where value.StartsWith(  
                string.Join(".", splitFqdn.Take(i)))  
            select value).ToList();
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22542052

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档