【问题标题】:Coding style: assignments inside expressions?编码风格:表达式中的赋值?
【发布时间】:2011-02-17 17:04:19
【问题描述】:

快速询问该社区的见解:哪个更可取?


选项①

// How many spaces are there in the beginning of string? (and remove them)
int spaces = text.Length;
text = text.TrimStart(' ');
spaces -= text.Length;
  • 优点:在单独的行上赋值,因此副作用是明确的
  • 缺点:第一行本身看起来很荒谬;你必须注意第三行才能理解它

选项②

// How many spaces are there in the beginning of string? (and remove them)
int spaces = text.Length - (text = text.TrimStart(' ')).Length;
  • 优点:语句在其执行的计算方面是有意义的
  • 缺点: 赋值有点隐藏在表达式中;副作用可以忽略

【问题讨论】:

  • 可爱的 Unicode 数字。
  • 我更喜欢第一种代码风格,因为第二种很难支持
  • 表达式中的赋值(一般的突变)通常[总是]错误(但请参阅MoveNext)——也就是说,它们使代码更难维护,更难推理。很容易查看第一个示例并选择“我应该使用更好的名称并避免对spaces 变量进行突变”。第二个只是令人困惑——有太多的事情需要在心理上进行跟踪。

标签: c# coding-style


【解决方案1】:

我不喜欢他们中的任何一个。编写清晰代码的一些准则:

  • 变量的含义应在变量的整个生命周期内保持不变。

选项 (1) 违反了本指南;变量“空格”被注释为“文本中有多少个空格”,但它实际上从来没有这个含义!它以文本中 字符 的数量开始其生命周期,并以文本中 过去 的空格数结束其生命周期。它在其整个生命周期中意味着两件不同的事情,而这两者都不是它所记录的意思。

  • 表达式语句只有一个副作用。 (“表达式语句”是由单个表达式组成的语句;在 C# 中,合法的语句表达式是方法调用、对象构造、递增、递减和赋值。)

  • 表达式没有副作用,除非表达式是表达式语句的单一副作用。

选项 (2) 显然违反了这些准则。产生多种副作用的表达式语句很难推理,它们也很难调试,因为你不能将断点放在你想要的位置,这很糟糕。

我会重写您的片段以遵循这些准则。

string originalText = text;
string trimmedText = originalText.TrimStart(' ');
int removedSpaces = originalText.Length - trimmedText.Length;
text = trimmedText;

每行一个副作用,每个变量在其整个生命周期中都意味着完全相同的东西。

【讨论】:

  • 美丽。 Eric,我喜欢从您的代码示例中学习(我从您的整数舍入代码中学到了很多东西)。您不仅编写了漂亮的代码,而且还具有解释您的编程理念的惊人能力。
  • Eric,我认为你应该在你的博客上开始一个“Pimp My Code”风格的代码审查,就像 Wil Shipley 对 Objective C 所做的那样 [wilshipley.com/blog/2005/07/code-insults-mark-i.html].甚至可以写一本简短的电子书。我很乐意支付您为此收取的任何费用。
  • +1 "变量的含义应该在变量的整个生命周期内保持不变。"听,听!
  • 实际上,我经常想知道的一件事是,如果调试器实际上可以正确地单步执行表达式,也许是通过一个新的“Step Into Expression”命令,那该有多酷……
  • @romkyns:就目前而言,您可以“步入特定”并在子菜单的表达式中选择一种方法。
【解决方案2】:

我会做选项 1b:

int initial_length = text.Length;
text = text.TrimStart(' ');
int spaces = initial_length - text.Length;

当然,它几乎是选项一的重复,但它更清晰一些(稍后您可能需要字符串的初始长度)。

【讨论】:

  • +1 非常感谢选项 1b!美妙之处在于变量的名称记录了计算,这总是一个好计划。
【解决方案3】:

我个人更喜欢选项 1。虽然选项 2 更简洁,并且工作正常,但我想到了在我继续前进后必须维护它的人,我想让我的代码尽可能易于理解。我可能知道作为表达式的赋值会计算为赋值的值,但下一个人可能不会。

【讨论】:

    【解决方案4】:

    过载怎么办?

    public static string TrimStart(this string s, char c, out int numCharsTrimmed) 
    {
        numCharsTrimmed = s.Length;
        s = s.TrimStart(c);
        numCharsTrimmed -= s.Length;    
    }
    

    【讨论】:

    • @pst -- 更何况?这不是至少让它成为一次性选择,而不是每次都要面对的事情吗?
    【解决方案5】:

    选项①全天。它是可读的。选项②更难维护。

    【讨论】:

      【解决方案6】:

      从您的问题本身的角度来看,我会说不要在表达式中进行分配,因为并非所有语言都支持它,例如 Python,所以如果您想在自己的个人编码风格中保持一致,您可以坚持传统的任务。

      【讨论】:

      • -1。用户显然在谈论 C# 代码并寻找输入。我认为我们不需要引入另一种编程语言来进行讨论。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-05-31
      • 1970-01-01
      • 1970-01-01
      • 2021-09-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多