先返回结果还是先将其存入变量中?

3
我可以在MVC应用程序中使用LINQ。我发现可以用两种方式创建方法,而且两种方式都能正常工作,但我不知道哪种更好。

直接:

public string GetStatus(int PersonId)
{
    return db.PersonStatus
        .Where(x => x.personid == PersonId)
        .Select(x => x.Status)
        .Single();
}

在一个变量first中:

public string GetStatus(int PersonId)
{
    string Item = db.PersonStatus
        .Where(x => x.personid == PersonId)
        .Select(x => x.Status)
        .Single();
    return Item;
}

我更喜欢第一种直接的方法,因为它似乎更有效率。请告诉我两种方法之间是否有显著差异,如果有,是什么?


4
这与LINQ无关。 - JLRishe
两者之间没有区别。我更喜欢第二个,因为它更易读和调试。 - crthompson
1
这没有关系,你确定要使用 Single 吗?如果 Where 返回超过1条记录,那么会抛出异常。 - evanmcdonnal
1
如果您的函数返回IQueryable<T>,请小心使用第一个选项,因为结果直到调用函数迭代可查询时才会实际评估。如果您正在使用闭包和其他东西(其中运行时将尝试在上下文消失后评估可查询),这可能会导致奇怪的错误。 - Neil Barnwell
@NeilBarnwell - 不管你在返回之前是否暂时存储了 IQueryable<T>,这个说法都是正确的吧? - Bobson
不用理我,傻瓜。 - Neil Barnwell
4个回答

5
据我所知,这两种方式是没有实际区别的(第二种可能会被优化为第一种)。使用LINQ和普通函数做这个操作也没有区别。但是,第二种方法更容易调试,因为你在计算结果后把它存储到某个地方,所以你可以在其中设置断点并检查该变量。尽管如此,我觉得第一种方法更清晰些。
以下是两个函数:
int Foo(int a, int b)
{
    int x = a+b;
    return x;
}

int Bar(int a, int b)
{
    return a+b;
}

以下是关闭优化后生成的IL代码(根据LINQPad):

Foo:
IL_0000:  nop         
IL_0001:  ldarg.1     
IL_0002:  ldarg.2     
IL_0003:  add         
IL_0004:  stloc.0     // x
IL_0005:  ldloc.0     // x
IL_0006:  stloc.1     // CS$1$0000
IL_0007:  br.s        IL_0009
IL_0009:  ldloc.1     // CS$1$0000
IL_000A:  ret         

Bar:
IL_0000:  nop         
IL_0001:  ldarg.1     
IL_0002:  ldarg.2     
IL_0003:  add         
IL_0004:  stloc.0     // CS$1$0000
IL_0005:  br.s        IL_0007
IL_0007:  ldloc.0     // CS$1$0000
IL_0008:  ret         

你会注意到Foo多了两行声明变量和读取变量的代码。
开启优化后的代码如下:
Foo:
IL_0000:  ldarg.1     
IL_0001:  ldarg.2     
IL_0002:  add         
IL_0003:  stloc.0     // x
IL_0004:  ldloc.0     // x
IL_0005:  ret         

Bar:
IL_0000:  ldarg.1     
IL_0001:  ldarg.2     
IL_0002:  add         
IL_0003:  ret    

再次添加一个额外的任务和负载。你几乎不会感觉到有什么差别。


2
优秀的分析!+1 在这种情况下可能并不是非常适用,但值得一提的是,过早地进行优化是万恶之源。 :) - crthompson
1
+1 - 这是一个很好的答案 - 很高兴看到深入的分析和警告,说明它不会并排出现。我有点惊讶它没有被优化掉。 - Gareth Latty
@Lattyware - 我也是,实际上。 - Bobson
@Bobson - 非常感谢你! - BattlFrog

3

我想在执行时这两个选项是没有区别的(我想这将被优化成完全相同的结果)。

第一种选择更为简洁,而后者则提供了明显的断点,并且很容易在以后需要与查询一起使用更多代码时插入。尽管如此,在这种情况下添加代码也相当容易。只需选择最适合你的那种方式即可。


0

没有显著的区别。我更喜欢第一个,尽管如果你使用第二个,调试可能会更容易,这样你就可以看到你正在返回什么。此外,如果你可能需要对返回的内容进行一些更改,你可能最终会转向第二种方式。


0

没有区别。除非我在调试并想观察结果,否则我更喜欢第一个选项。

如果您的函数返回IQueryable<T>,请小心第一个选项,因为直到调用函数迭代可查询对象时,结果才会真正被评估。如果您正在使用闭包和其他内容(其中运行时将尝试在其上下文消失后评估可查询对象),则可能会导致奇怪的错误。


如果您存储并返回 IQueryable<T>,这种情况仍然会发生,不是吗? - Bobson
嗯,好的观点 - 我在想可能会忘记调用ToList或类似的方法。 - Neil Barnwell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接