C# 试图优化if/else条件会降低程序速度

C# 试图优化if/else条件会降低程序速度,c#,optimization,compiler-construction,C#,Optimization,Compiler Construction,我目前正试图在VS分析工具的帮助下优化.net应用程序 一个经常被调用的函数包含以下代码: if (someObjectContext.someObjectSet.Where(i => i.PNT_ATT_ID == tmp_ATT_ID).OrderByDescending(i => i.Position).Select(i => i.Position).Count() == 0) { lastPosition = 0; } else { lastPositi

我目前正试图在VS分析工具的帮助下优化.net应用程序

一个经常被调用的函数包含以下代码:

if (someObjectContext.someObjectSet.Where(i => i.PNT_ATT_ID == tmp_ATT_ID).OrderByDescending(i => i.Position).Select(i => i.Position).Count() == 0)
{
    lastPosition = 0;
}
else
{
    lastPosition = someObjectContext.someObjectSet.Where(i => i.PNT_ATT_ID == tmp_ATT_ID).OrderByDescending(i => i.Position).Select(i => i.Position).Cast<int>().First();
}
if(someObjectContext.someObjectSet.Where(i=>i.PNT\u ATT\u ID==tmp\u ATT\u ID).OrderByDescending(i=>i.Position).选择(i=>i.Position).Count()==0)
{
lastPosition=0;
}
其他的
{
lastPosition=someObjectContext.someObjectSet.Where(i=>i.PNT\u ATT\u ID==tmp\u ATT\u ID).OrderByDescending(i=>i.Position).选择(i=>i.Position).Cast().First();
}
我把它改成这样:

var relevantEntities = someObjectContext.someObjectSet.Where(i => i.PNT_ATT_ID == tmp_ATT_ID).OrderByDescending(i => i.Position).Select(i => i.Position);
if (relevantEntities.Count() == 0)
{
    lastPosition = 0;
}
else
{
    lastPosition = relevantEntities.Cast<int>().First();
}
var relevantEntities=someObjectContext.someObjectSet.Where(i=>i.PNT_ATT_ID==tmp_ATT_ID).OrderByDescending(i=>i.Position).选择(i=>i.Position);
if(relevantEntities.Count()==0)
{
lastPosition=0;
}
其他的
{
lastPosition=relevantEntities.Cast().First();
}
我希望这一更改会使方法加快一点,因为我不确定编译器是否会注意到查询已完成两次并缓存结果

令我惊讶的是,该方法的执行时间(inklusive采样数)没有减少,甚至增加了9%(根据分析器)

有人能解释为什么会发生这种情况吗?

如果没有与您的条件匹配的实体,您可以使用
Max()
获得最大位置,而不是订购和获取第一项,并且
DefaultIfEmpty()
提供默认值(int为零)。顺便说一句,如果序列为空,您可以提供自定义默认值以返回

lastPosition = someObjectContext.someObjectSet
                                .Where(i => i.PNT_ATT_ID == tmp_ATT_ID)
                                .Select(i => i.Position)
                                .Cast<int>()
                                .DefaultIfEmpty() 
                                .Max();
lastPosition=someObjectContext.someObjectSet
.其中(i=>i.PNT\u ATT\u ID==tmp\u ATT\u ID)
.选择(i=>i.位置)
.Cast()
.DefaultIfEmpty()
.Max();
因此,您将避免执行两个查询,一个用于定义是否存在任何位置,另一个用于获取最新位置。

您可以使用
Max()
获取最大位置,而不是排序和获取第一项,并使用
DefaultIfEmpty()
提供默认值(0表示int)如果没有与您的条件匹配的实体。顺便说一句,如果序列为空,您可以提供自定义默认值以返回

lastPosition = someObjectContext.someObjectSet
                                .Where(i => i.PNT_ATT_ID == tmp_ATT_ID)
                                .Select(i => i.Position)
                                .Cast<int>()
                                .DefaultIfEmpty() 
                                .Max();
lastPosition=someObjectContext.someObjectSet
.其中(i=>i.PNT\u ATT\u ID==tmp\u ATT\u ID)
.选择(i=>i.位置)
.Cast()
.DefaultIfEmpty()
.Max();
因此,您将避免执行两个查询—一个用于定义是否有职位,另一个用于获取最新职位

我希望这一更改会使方法加快一点,因为我不确定编译器是否会注意到查询已完成两次并缓存结果

不会的。事实上,它不能。对于这两个查询,数据库可能不会返回相同的结果。在第一次查询之后、第二次查询之前,完全可以添加或删除结果。(这不仅使代码效率低下,而且如果发生这种情况,代码可能会被破坏。)由于您完全有可能希望执行两个查询,并且知道结果可能不同,因此不要重复使用查询的结果,这一点很重要

这里的重点是延迟执行的思想<代码>相关实体不是查询的结果,而是查询本身。直到迭代了
IQueryable
(通过
Count
First
、foreach循环等方法)之后,才会查询数据库,每次迭代查询时,它都会对数据库执行另一个查询

在您的情况下,您可以这样做:

var lastPosition = someObjectContext.someObjectSet
    .Where(i => i.PNT_ATT_ID == tmp_ATT_ID)
    .OrderByDescending(i => i.Position)
    .Select(i => i.Position)
    .Cast<int>()
    .FirstOrDefault();
var lastPosition=someObjectContext.someObjectSet
.其中(i=>i.PNT\u ATT\u ID==tmp\u ATT\u ID)
.OrderByDescending(i=>i.Position)
.选择(i=>i.位置)
.Cast()
.FirstOrDefault();
这利用了一个事实,即
int
的默认值为0,这是您在之前不匹配的情况下设置该值的值

请注意,这是一个功能与您的查询相同的查询,它只是避免了执行两次。一个更好的查询应该是您所建议的查询,它利用了
Max
,而不是排序并使用第一个查询。如果该列上有一个索引,则不会有太大的差异,但如果没有索引排序,则成本会高得多

我希望这一更改会使方法加快一点,因为我不确定编译器是否会注意到查询已完成两次并缓存结果

不会的。事实上,它不能。对于这两个查询,数据库可能不会返回相同的结果。在第一次查询之后、第二次查询之前,完全可以添加或删除结果。(这不仅使代码效率低下,而且如果发生这种情况,代码可能会被破坏。)由于您完全有可能希望执行两个查询,并且知道结果可能不同,因此不要重复使用查询的结果,这一点很重要

这里的重点是延迟执行的思想<代码>相关实体不是查询的结果,而是查询本身。直到迭代了
IQueryable
(通过
Count
First
、foreach循环等方法)之后,才会查询数据库,每次迭代查询时,它都会对数据库执行另一个查询

在您的情况下,您可以这样做:

var lastPosition = someObjectContext.someObjectSet
    .Where(i => i.PNT_ATT_ID == tmp_ATT_ID)
    .OrderByDescending(i => i.Position)
    .Select(i => i.Position)
    .Cast<int>()
    .FirstOrDefault();
var lastPosition=someObjectContext.someObjectSet
.其中(i=>i.PNT\u ATT\u ID