为什么IF语句会影响我的LINQ语句的结果?

时间:2012-11-26 16:50:57

标签: c# linq sharepoint

我最近在LINQ上工作过一段时间,感谢StackOverflowers的帮助,我得到了这个声明:

var traceJob =
    from jobDefinition in service.JobDefinitions
    where jobDefinition.Id == traceGuid
    select jobDefinition;

if (traceJob != null && traceJob.Count() == 1)
{
 traceJob.First().RunNow();
 Console.WriteLine(traceJob.First().DisplayName + "  Last Run Time: " + traceJob.First().LastRunTime);
}

然而,我感到困惑,因为使其有效的作品是if(traceJob.Count() ==1)。如果我删除该部分,则会收到ObjectNullRef错误,指出traceJob的枚举没有产生任何结果。

现在,据我所知,检查计数的if语句实际上不应该改变Linq语句的结果吗?任何人都可以向我解释为什么我会看到这种行为吗?

5 个答案:

答案 0 :(得分:6)

不,不应该。我的猜测是你遇到了枚举真的是空的情况,并通过检查计数> 0,First()不会失败。

作为旁注,Any()可能是更好的检查(取决于您的存储库的底层存储),它可能比Count()更快:

if (traceJob != null && traceJob.Any())
{
 traceJob.First().RunNow();
 Console.WriteLine(traceJob.First().DisplayName + "  Last Run Time: " + traceJob.First().LastRunTime);
}

答案 1 :(得分:4)

var traceJob =
    (from jobDefinition in service.JobDefinitions
    where jobDefinition.Id == traceGuid
    select jobDefinition).SingleOrDefault();

您可以使用singleOrDefault检查单个结果。它将返回与where条件匹配的结果,如果未找到匹配则返回null。如果找到多个匹配的查询,则会抛出异常。

这涵盖了您的tracejob == null以及tracejob.count == 1条件。

MSDN Article

答案 2 :(得分:2)

我不知道您的“服务”的实际实现,但通常linq查询实际上仅在请求时填充其结果。所以Count()确实改变了traceJob的状态,很可能是填充内部集合。看起来First()不会填充内部集合,或者即使它通常也应该正确地执行它。

答案 3 :(得分:2)

关于https://stackoverflow.com/a/1745716/1289709
我认为在这里使用FirstOrDefault会更合理。

  

每当您使用SingleOrDefault时,您都清楚地说明了该查询   最多应该产生一个结果。另一方面,当   使用FirstOrDefault,查询可以返回任何数量的结果但是   你声明你只想要第一个。

所以将代码更改为:

var traceJob = (from jobDefinition in service.JobDefinitions
    where jobDefinition.Id == traceGuid
    select jobDefinition).FirstOrDefault();

    if (traceJob != null)
    {
       traceJob.RunNow();
       Console.WriteLine(traceJob.DisplayName + "  Last Run Time: " + traceJob.LastRunTime);
    }

答案 4 :(得分:2)

我认为你的问题源于linq语句在被调用时的执行方式,而不是它们被声明的位置。

所以你的陈述:

var traceJob =
    from jobDefinition in service.JobDefinitions
    where jobDefinition.Id == traceGuid
    select jobDefinition;

这大致在功能上等同于:

IEnumerable<JobDefinition> GetJobDefinitions(YourService service, Guid traceGuid) 
{
    foreach(var jobDefinition in service.JobDefinitions) 
        if(jobDefinition.Id == traceGuid) 
            yield return jobDefinition;
}

因此,当您致电traceJob.Count()时,您的工作相当于调用GetJobDefinitions(service, traceGuid).Count(),每次拨打traceJob.First()时,您都会再次点击循环。

如果可以一遍又一遍地调用service.JobDefinitions,这可能不是问题。但是,如果结果随时间而变化(例如,如果在执行期间添加了作业),或者如果后续运行具有不同的结果,则会出现问题。

在任何情况下,您最好只执行一次循环:

var traceJobs =
    from jobDefinition in service.JobDefinitions
    where jobDefinition.Id == traceGuid
    select jobDefinition;

// This is where the loop above actually executes - if it's empty it will return null
var firstJob = traceJobs.FirstorDefault();

if(firstJob != null)
{
    firstJob.RunNow();
    Console.WriteLine(firstJob.DisplayName + "  Last Run Time: " + firstJob.LastRunTime);
}

或者,您可以通过将循环转换为列表或数组来强制循环执行:

var traceJobsExecuted = traceJobs.ToList();