嵌套函数调用 - 最佳实践是什么?

10

这是一个小事,但我会很乐意听听其他人对它的看法。

以下两个代码片段中哪个是最佳编程实践?

var results = GetResults();

SendResults(results);

或者:

SendResults(GetResults());

我认为第一个选项更好,但另一方面,选项2需要编写(和阅读)的代码较少。你怎么想?
我知道这是一个非常基础的问题,但仍然...

我想这取决于结果是否仅由SendResults使用。如果是的话,我会将GetResults()放在SendResults()调用内部,这样你的调用看起来就像是SendResults()。我会将其设置为私有方法,以便类外的其他方法无法调用GetResults()。如果GetResults()将在其他区域中被调用,则我会给它一个更好的名称,并尝试正确地oop该类。 - TheKingDave
12个回答

9
我通常选择第一种选项,因为这样我可以在调用GetResultsSendResults之间插入断点。
如果代码是在方法的中间,那通常不会有太大问题,但如果它是以下形式的:
 return Process(GetData());

在调用GetDataProcess函数后,它们的返回值并不是直观可见的。除非我们调用的是一个没有副作用且结果显而易见的框架函数(比如int.Parse),否则我更喜欢以下格式:

var data = GetData();
var result = Process(data);
return result;

6

This

var results = GetResults();
SendResults(results);

使用它更易于调试...尝试在SendResults(results)上设置断点并查看结果的值。

这非常重要,以至于在下一个版本的Visual Studio(即2013)中,他们正在添加一种查看函数返回值的方法(例如,请参见此处

这个新功能允许您检查函数的返回值,当开发人员在调试会话期间步过或跳出函数时。当返回值未存储在本地变量中时,这尤其有用。考虑以下嵌套函数示例Foo(Bar()); 在这个示例中,当您步过那行时,现在可以检查来自Bar和Foo的返回值。

从编译的角度来看,它们通常是相同的。在IL级别上唯一的区别是堆栈中的某个插槽具有一些元信息与变量的名称(results),或者没有名称。


我不知道他们在VS2013中添加了它。这是一个非常有用和期待已久的功能... - Shai Aharoni

4

我认为你应该始终追求清晰明了,所以我更喜欢:

// notice the type not var (unless it's obvious)
IEnumerable<MyClass> results = GetResults();

SendResults(results);

1
处理此类问题时的第一原则应该是可读性(如果不涉及某些低级别的优化)。在您的简单示例中,可读性是可以比较的,但请考虑像这样的代码:
SendResults(GetResults(Sorter, context.GetCurrentPageInfo(userContext), ...);

当然,更清晰的表述应该是:


var results = GetResults();
var pageInfo = context.GetCurrentPageInfo(userContext);
...
SendResults(results, pageInfo, ...);

正如其他答案所指出的那样,更易读的版本有一个优点 - 更容易调试,因为您可以检查所有中间值。


1

这完全取决于个人开发者。这是非常主观的事情。

就我个人而言,我更喜欢第一个版本,因为如果需要的话,我可以更容易地通过调试器逐步查看代码。

在TDD(测试驱动开发)的支持者中,有些人会非常狂热地认为这并不重要,因为如果你做TDD“正确”,你永远不会使用调试器。

我也更喜欢较小的行,因此,如果您有一个方法调用,该调用传递其他方法调用的结果和参数列表开始变得过多,那么阅读起来就会变得非常困难。

SendResults(GetResults(arg0, arg1, arg2), SomeOtherMethod(arg3, arg4), arg5);

这开始变得相当难以阅读和跟踪所有内容。

最终,这是你的系统,你需要维护它,所以无论你找到哪种风格更容易就采用哪种。


1
var results = GetResults();
SendResults(results);

这样做是可以接受的,因为它允许使用断点来检查results的值。一些编程语言可能不会对此代码进行优化,因此代码检查可能会发出警告,表示变量results从未被修改。C#很可能会进行优化,所以没有问题。

对于以下示例,代码检查器可能会发出有关低效代码的警告;

 var results = GetResults();
 return results;

这取决于编程语言,我认为C#在优化方面没有问题。


1

我知道这已经很老了,但是在Visual Studio 2017中,参数不再需要基于调试的便利性。有一种新的处理嵌套调用的方法。在具有嵌套调用的行上设置断点。当断点命中时,您可以使用“Step Into Specific”上下文菜单(右键单击)命令进入任何层次的嵌套。这将显示从最内层到最外层的顶部呼叫。这包括lambda函数(例如LINQ谓词)。

enter image description here


1

个人而言,我更喜欢第一个选项,因为在调试时您可以检查GetResults()的结果。

我认为这与编程实践无关,更多的是个人风格。


0
如果结果是以这种方式使用的,我可能会选择另一种解决方案:
class SomeClass
{
    private MyClass _results;
}

private void SendResults()
{
   ... // Implementation which sets _results

SendResults 直接从 _results 获取结果,不需要使用 GetResults(除非它被其他类使用),因此代码可以简化为:

public MyClass Results { get; private set; }

0
在我看来,这并不太重要,但我稍微倾向于第一种方式,因为它使得阅读和扩展以及维护都稍微容易一些。在我看来,更重要的是保持一致性。选择其中一种方式,而不是两种方式都用。

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