【问题标题】:Are 'TryAction()' methods evil?'TryAction()' 方法是邪恶的吗?
【发布时间】:2012-06-15 19:08:32
【问题描述】:

我正在尝试改进我的代码中的 FxCop 合规性(这是有史以来的第一次),但我有点陷入道德问题。我有一个方法GetText() 从远程服务器返回一个字符串,但在某些情况下会抛出异常。这就是为什么我还有一个方法TryGetText(ByRef text As String),它返回一个布尔值,指示调用是否成功。如果为 true,则将返回值赋给 text 变量。

我认为这种结构是完全可以接受的,考虑到即使是微软也这样做(例如Integer.TryParse)。 不过,FxCop 对我嗤之以鼻,口授“你不能通过引用传递!”

为了规避这个警告(其中有很多),我用 StringBuilder 替换了参数。但尽管现在符合要求,但我认为它并没有真正改善我的代码。

之前:

    Public Function TryGetText(ByRef text As String) As Boolean
        Dim command As New GetTextCommand(Me)
        Dim result As CommandResult = ProcessCommand(command, True)
        If result.CommandStatus <> Constants.Status.Failed Then
            text = result.Text
            Return True
        Else
            Return False
        End If
    End Function

之后:

    Public Function TryGetText(builder As Text.StringBuilder) As Boolean
        Dim command As New GetTextCommand(Me)
        Dim result As CommandResult = ProcessCommand(command, True)
        If result.CommandStatus <> Constants.Status.Failed Then
            builder.Clear()
            builder.Length = result.Text.Length
            builder.Append(result.Text)
            Return True
        Else
            Return False
        End If
    End Function

这是可接受的 ByRef 用法,还是我应该使用 stringbuilder 替代方法?对于使用此构造的每种方法,我都对抑制此警告感到不舒服。我也不觉得 stringbuilder 变体提高了代码可用性。

【问题讨论】:

    标签: vb.net pass-by-reference fxcop


    【解决方案1】:

    这可能是ByRef 的一个很好的用法,所以我倾向于为这种情况添加一个例外。如果您使用 Visual Studio 中的代码分析功能,您只需在方法中添加以下属性:

    <System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", MessageId = "1#")> _
    Public Function TryGetText(ByRef text As String) As Boolean
    

    【讨论】:

      【解决方案2】:

      TryAction 方法在创建线程安全类之类的东西时非常有用。它将测试和操作这两个步骤组合成一个原子操作。 Microsoft 在并发集合类中大量使用它。例如http://msdn.microsoft.com/en-us/library/dd287191.aspx#Y0

      所以我认为“您不得通过引用传递”的笼统声明。不应该在所有情况下都被视为福音。有合法用途。在您的具体情况下, ByRef 似乎没有 StringBuilder 版本那么笨拙。但是,如果在您当前返回 false 的情况下返回 null/Nothing 的简单 string GetText() 是等效的,那似乎是最好的。

      【讨论】:

      • 在这种情况下,我不能让它只返回 null,因为 null 将是我正在做的事情的有效值。所以我想这证实了它是正确使用 ByRef。
      • +1 这些规则是好仆人,却是坏主人。绝不应盲目服从。
      【解决方案3】:

      嗯,我认为每个人都讨厌太多的 byref。两个已经太多了。尽管在您的情况下有很多方法并且它们都遵循相同的模式,但这听起来并不是一个真正的问题。 您可以选择不遵循 Microsoft 的 Try* 方法模式。

      为什么不返回布尔值,如果成功则返回字符串,如果失败则返回 Nothing/Empty? 然后您可以使用 String.IsNullOrEmpty(resultText) 测试您的 TryGetText 输出。

      确实是更多的代码,但它确实解决了警告(如果这真的是你所追求的)。

      【讨论】:

      • 我本可以这样做,但 null(或空)(甚至空格)都是可能的返回值。只有当服务器拒绝返回文本时,调用才会失败。我的代码需要知道它是否失败或者服务器是否返回了一个空字符串。
      • 那你最好使用 byref 和 SuppressMessageAttribute。除了实际的字符串结果之外,您还可以通过将响应包装在可以告诉您操作状态的内容中来使事情复杂化。
      • 我猜是使用这些所谓的元组?我可能应该调查一下。我认为我以前从未使用过元组......
      • 是的,这将是一种方法,可以省去一个自定义类。最简单的元组就像字典中的 KeyValuePair。它们最多有 8 个可能的条目,但我认为您只需要一个 Tuple。更多信息:msdn.microsoft.com/en-us/library/dd387181.aspx
      • 这是很棒的东西!我想知道为什么微软从不在基类库中使用元组。只要您使用 XML cmets 正确标记返回值,这似乎就简单多了。或者您知道如何将元组属性 (Item1, Item2,...) 重命名为更具描述性的名称吗? (编辑:我才意识到这是个多么愚蠢的问题。)
      【解决方案4】:

      当您尝试以函数式样式使用您的方法时,通过引用传递会使事情变得复杂。您可以考虑使用可为空的类型或元组或您自己的 Option 类型。

      由于我对VB不太熟悉,这里以C#为例:

      struct Option<T> {
         public bool ContainsElement { get; private set; }
         private T element;
         public T Element {
            get {
               if (!ContainsElement) throw new NoElementException ();
               return element;
            }
            set {
               element = value;
               ContainsElement = true;
            }
         }
         public T GetElementOrDefault (T defaultValue) {
            return ContainsElement ? element : defaultValue;
         }
      }
      
      Option<string> GetText () {
         ...
      }
      

      【讨论】:

      • 你能在 C# 中创建可空字符串吗?我检查以确保但它不允许我进入 VB(尽管 String 在其他方面表现得像一个值类型)。
      • 不,你不能,因为字符串已经是一个对象。但是,您可以按照上面的建议直接返回 null。我的回答应该是:对值类型使用可空类型;对于引用类型,返回 null。然而,“干净”的方式可能是 Option 类,因为许多函数式语言都是这样做的。
      猜你喜欢
      • 2011-01-02
      • 1970-01-01
      • 2011-12-07
      • 1970-01-01
      • 1970-01-01
      • 2016-11-18
      • 2010-11-26
      • 2020-08-10
      • 2010-12-23
      相关资源
      最近更新 更多