【问题标题】:returning an assignment expression返回一个赋值表达式
【发布时间】:2013-08-29 04:05:47
【问题描述】:

当我使用 C# 编写一些较旧的代码时,我遇到了一个令我厌烦的代码。

事不宜迟,如下:

private string foo(string _text)
{
   /* some manipulation on _text */
   return _text = Server.HtmlDecode(_text);
}

让我恼火的是最后一行;我来自 C 背景,我可以理解代码实际上是在尝试返回解码的 _text 变量。赋值运算符的值也是左操作数,所以我可以看到它。

但我仍然觉得它很烦人。

这是我需要习惯的 C# 中的常规练习吗?

对我来说最后一行应该是

return Server.HtmlDecode(_text);

而不是赋值表达式。是否有我不知道的更深层次的 C# 功能?

【问题讨论】:

  • _text 绝对不是全局变量,而是方法的参数。
  • 作业真的有必要吗?之后您将无法对 _text 执行任何操作,而且它很可能超出范围。
  • @lc。这就是我部分要求的;如果它有任何意义。根据我收集到的信息,我想不会。
  • @JaceKim 不这么认为。它可能从_text 是一个字段的时候重构,在这种情况下foo 会设置_text 的值并返回值?
  • @lc。不幸的是,这是一个新的承诺。无论如何,问题已经得到解答,我很满意。谢谢大家。

标签: c# string return variable-assignment operator-keyword


【解决方案1】:

当我使用 C# 编写一些较旧的代码时,我遇到了一个令我厌烦的代码。

这里有许多令人讨厌的问题。让我们把它们都列出来。

private string foo(string _text)
{
   /* some manipulation on _text */
   return _text = Server.HtmlDecode(_text);
}

最后一句让我很烦

评论也令人讨厌。局部变量便宜。无需删除_text 的原始值。相反,创建一个新的局部变量并对其进行操作。这样,当您在方法中的任何一点调试时,您都可以知道原始参数是什么。 (请记住,在变量被覆盖的那一刻,原始参数可能有资格进行垃圾回收,因此可能永远丢失。)

不要在没有充分理由的情况下重写形式参数。它使调试变得更加困难。

赋值运算符的值是左操作数,所以我可以看到。

在这种情况下是正确的,但总体上是错误的; C#中赋值运算符的值是右侧操作数转换为左侧相关类型后的值。请记住,左侧可能没有值;它可能是只写属性。

这是我需要习惯的 C# 中的常规练习吗?

这里有一个标准做法,是的。这种用法的奇怪之处在于(1)选择的变量是正式的,以及(2)赋值与return结合。

这是 C# 的标准做法:

string decoded = Server.HtmlDecode(_text);
return decoded;

现在您可能想知道,与您的建议相比,这有什么令人信服的好处:

return Server.HtmlDecode(_text);

答案是:在 Visual Studio 2013 之前,调试器中没有工具可以检查方法调用的返回值!因此,如果您想查看HtmlDecode 在调试时返回的值是什么,您有以下选择:

  • 在汇编级别调试并查看 EAX 的内容
  • 进入HtmlDecode 并检查其状态
  • 跳出当前方法并检查分配给的返回值
  • 将结果分配给其他无用的局部变量,然后在调试器中检查局部变量

由于前三个很可怕,最后一个很简单,这就是许多 C# 程序员的习惯。

如果你这样做然后使用生成的本地,C# 编译器知道这是一种常见的做法,并故意抑制“你写到本地然后从不读取”警告.只有在本地写入常量时才会发出警告,在这种情况下,您在编译时就已经知道它是什么,通常不需要在调试器中检查它。

希望现在 VS2013 终于支持这个经常被要求的功能,这种模式会逐渐消失。

【讨论】:

  • 如果可以的话,您介意扩展一下这句话吗? “请记住,在变量被覆盖的那一刻,原始参数可能有资格进行垃圾收集,因此可能永远丢失”
  • @Jace Kim:如果变量被覆盖,则可能是参数没有剩余的实时引用,GC 可以收集它。
【解决方案2】:

此语句是多余的,不是 C# 实践。

在 ReSharper 处于活动状态时这样做也会发出警告

分配的值不用于任何执行路径

正如你所说,这段代码确实是最佳实践

return Server.HtmlDecode(_text);

此外,由于解码是对 _text 的操作的一部分,因此将赋值语句和返回语句分开也是有效的,以将逻辑保持在同一块中:

/* Other manipulations on _text */
_text = Server.HtmlDecode(_text);

return _text;

【讨论】:

    【解决方案3】:

    不,在这种情况下没有更深层次的 C# 功能,在 return 语句中进行赋值是毫无意义的。它只会让你更难遵循代码应该做的事情。

    与您建议的唯一区别是解码后的值被分配给_text 变量,但由于不再使用该变量,因此方法结束时它的值是什么并不重要。该参数是方法内部的局部变量,不会影响方法外部的任何内容。

    【讨论】:

    • 接下来的问题是,return 语句是否返回 _text 的值,或者“赋值表达式的结果”。这是一个非常迂腐的问题。 C# 程序员是否使用“赋值表达式的值”?为了在 C 语言中的可读性,我避免使用它,但我已经看到足够多的代码使用它来厌倦它。
    • @JaceKim:return 语句返回表达式的值,赋值表达式的值就是被赋值的值。该值不会再次从变量中读取以返回。 C# 程序员有时使用赋值作为表达式,但不是很频繁。它主要用于替代方案是更复杂的控制结构时,例如当一个值确定循环是否应该继续时; while ((line = stream.ReadLine()) != null) ...
    【解决方案4】:

    不,这样做很愚蠢,而且以在一行中塞入更多代码的名义牺牲了可读性。这几乎总是一件坏事。

    在这种情况下,它实际上没有任何作用。 _text 是方法的参数,在方法体中更改它没有任何作用。传递给方法的字符串不会被修改。

    【讨论】:

      【解决方案5】:

      它们的结果相同。最常见的是后者,或者:

      _text = Server.HtmlDecode(_text);
      return _text;
      

      (我喜欢上面的或return Server.HtmlDecode(_text);,但不是你正在阅读的代码中的方式)

      【讨论】:

      • 我更喜欢Server.HtmlDecode(_text);。话虽如此,我更喜欢使用本地声明的字符串来存储字符串操作。
      • 好的。我只是想知道是否有一些我不知道或找不到的晦涩的 C# 功能。来自 C 和 Lisp,C# 似乎背后有很多黑魔法。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多