创建一次性变量是一个好的编程实践吗?

26

我的一个同事重构了这段代码:

private void btnGeneral_Click(object sender, RoutedEventArgs e)
{
    Button button = (Button)e.OriginalSource;
    Type type = this.GetType();
    Assembly assembly = type.Assembly;
    string userControlFullName = String.Format("{0}.{1}", type.Namespace, button.Name);
    UserControl userControl = (UserControl)assembly.CreateInstance(userControlFullName);
}

对于这段代码:

private void btnGeneral_Click(object sender, RoutedEventArgs e)
{
    Button button = (Button)e.OriginalSource;
    Type type = this.GetType();
    Assembly assembly = type.Assembly;
    UserControl userControl = (UserControl)assembly.CreateInstance(String.Format("{0}.{1}", type.Namespace, button.Name));
}

有人说如果一个变量只使用一次,就不需要创建变量。

我的回答是,创建仅使用一次的变量是好的做法,因为:

  • 它作为注释并减少了注释(“userControlFullName”是清晰的)
  • 使代码更容易阅读,即更多的代码“像英语一样阅读”
  • 通过使用清晰的变量名称替换其中的部分,避免了过长的语句
  • 更容易调试,因为您可以将鼠标悬停在变量名称上,在某些情况下,例如PHP编程时,如果没有调试器,则更容易输出这些变量名称以获取其值

反对此方法的论点“代码行数更多”,“存在不必要的变量”是为了让编译器更轻松而提出的,但没有显著的速度或资源节省。

是否有人能想到任何不应创建仅使用一次的变量名称的情况?


2
我会将他的代码重构为你的代码。简洁和清晰是首要的。你的代码更容易理解,这是一个重要的原因。 - Daniel Daranas
1
只是提醒一下:PHP 有调试器...(Zend、xdebug) - Christian Studer
14个回答

34

在这种情况下,我同意你的观点。易读性非常重要。但我也不会主张“总是使用只使用一次的变量”。例如:

String name = "John";
person.setName(name);

是不必要的,因为

person.setName("John");

阅读起来同样流畅——甚至更好。但是,当然,并非所有情况都那么清晰明了。“易读性”毕竟是一个主观的术语。


24

你提出的所有理由在我看来都是合理的。

有些情况下,你必须避免使用中间变量,需要一个单一表达式(例如在Java/C#中的成员变量初始化),但在适用时引入额外的变量以增强可读性绝对没有问题。显然不要为每个方法的每个参数都这么做,但适度使用可以帮助很多。

其中调试的原因尤其重要-能够跳过“准备”方法参数的行并直接进入方法本身,在调试器中轻松查看参数后,就非常好了。


20

你的同事似乎不够一致。

一致性的解决方案如下所示:

private void btnGeneral_Click(object sender, RoutedEventArgs e)
{
    UserControl userControl = ((UserControl)type.Assembly).CreateInstance(String.Format("{0}.{1}", this.GetType().Namespace, ((Button)e.OriginalSource).Name));
}

6

我完全同意你的观点。

特别是在方法需要很多布尔值的情况下,我会使用这个。

public void OpenDocument(string filename, bool asReadonly, bool copyLocal, bool somethingElse)

对我来说,这更易读:
bool asReadonly = true;
bool copyLocal = false;
bool somethingElse = true;

OpenDocument("somefile.txt", asReadonly, copyLocal, somethingElse);

..比:

OpenDocument("somefile.txt", true, false, true);

我会使用 "OpenDocument("somefile.txt", /asReadonly=/true, /copyLocal=/false, /somethingElse=/true);",如果需要可以进行分栏。当然,合理的枚举类型更好 :) - Simon Buchan

5

由于我使用的编程语言通常无法告诉我异常堆栈跟踪中的空值是什么,因此我通常尝试使用变量,以便每行最多只能有一个项为空。实际上,我发现这是限制我想要在单个行上放置多少语句的最重要限制因素。

如果您从生产日志中的此语句中获得nullpointerexception,则真的会遇到麻烦:

getCustomer().getOrders().iterator().next().getItems().iterator().next().getProduct().getName()

虽然我同意您的想法,但添加额外的变量可能会在方法中引入一个额外的概念,并且该概念可能并不总是与方法的整体目标相关。因此,过度添加变量也可能会增加方法复杂性并降低可读性。请注意这里“过度”的使用。


我不同意。与令人烦恼的长行相比,额外的变量并没有“引入”额外的概念;相反,它通过赋予其名称来解释已经存在的概念。 - Daniel Daranas
在微小的编辑中,添加了关于“过度”和与整体目标相关性的澄清。 - krosenvold
同意Daniel Daranas所说的 =) - Brock Woolf
你引入的变量应该与方法的主要意图仍然相关。否则,你只是在增加无用的内容。 - krosenvold
或者,正如我所说,这应该是出于技术原因(NullPointerExceptions)的相关内容。 - krosenvold
正是因为这个原因,我在使用单次使用变量方面非常勤奋... 这使我能够在进一步使用变量之前检查每个变量是否为空/空白。 - Cerebrus

3

我猜在某些情况下,这可能会影响性能。特别是在这个例子中:

for (int i1 = 0; i1 < BIG_NR; i1++)
{
  for (int i2 = 0; i2 < BIG_NR; i2++)
  {
    for (int i3 = 0; i3 < BIG_NR; i3++)
    {
      for (int i4 = 0; i4 < BIG_NR; i4++)
      {
        int amount = a + b;
        someVar[i1][i2][i3][i4] = amount;
      }
    }
  }
}

…额外的任务可能会对性能产生过大的影响。 但总的来说,你的论点是100%正确的。


2
任何一款还算不错的编译器/虚拟机都会对其进行优化。但在这个例子中,变量对于可读性来说并不是必需的,因为表达式作为内联方式阅读起来同样好或更好。 - Lawrence Dol

2
这两个代码完全相同。当然,你的更易读、易于维护和调试,但如果你同事的目标不是这些,他的代码就不是无内存消耗的。

2

我认为这是根据你想要代码的整洁程度来判断的。我也认为你和你的同事都是正确的。

在这种情况下,基于你提供的代码(出于性能原因),我会支持你的同事,但正如我之前所说,它确实取决于它将被用于的上下文环境,我认为你的立场是完全可以接受的。

我想指出的是,为一次使用的参数创建变量可能是没有意义的,除非它们是const变量或者是你需要在许多地方使用的东西。

我认为声明一个仅使用一次的变量可能会在调试时造成更多的混乱,如果有很多这样的变量存在的话,但偶尔出现一两个应该没问题。


2
创建一个新变量意味着读者需要多掌握一个概念。(考虑极端情况:int b=a;c=b;) 如果一个方法如此复杂——需要拆分——以至于额外的概念是值得付出的代价,那么你应该全面拆分它成为两个方法。这样你既可以获得有意义的名称,又可以减小方法的大小。(对于原始方法来说更小:如果像你所说的那样,人们通常不需要阅读辅助方法。)
这是一种概括,尤其是在一种需要添加大量样板代码的语言中,但你不会经常反对这种概括,使其成为你的风格指南值得注意。

2

我原则上完全同意你的同事,但在这种情况下不同意。

使用一次性变量的问题在于它们引入了状态,而更多的状态意味着代码更难理解,因为你不知道它可能对程序流程产生什么影响。函数式编程根本没有任何变量,正是出于这个原因。因此,变量越少越好。消除变量是有益的。

然而,在这种特殊情况下,当方法在变量的唯一使用之后立即结束时,拥有它的缺点很小,而你提到的优点可能更加重要。


在避免状态方面提到函数式编程是个好主意,我听了一个关于F#的播客,但是无法理解为什么在那种语言中变量是如此不同寻常的东西(我知道在F#中所有“变量”都是常量,这是个矛盾之处,因此很令人困惑)。 - Edward Tanguay

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