4

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

我认为这种结构是完全可以接受的,考虑到即使是微软也这样做(例如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 变体提高了代码可用性。

4

4 回答 4

2

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

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

于 2012-06-15T19:28:29.023 回答
2

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

<System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", MessageId = "1#")> _
Public Function TryGetText(ByRef text As String) As Boolean
于 2012-06-15T19:23:40.523 回答
0

当您尝试以函数式样式使用您的方法时,通过引用传递会使事情变得复杂。您可能会考虑使用可为空的类型或元组或您自己的 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 () {
   ...
}
于 2012-06-15T19:40:47.483 回答
0

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

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

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

于 2012-06-15T19:24:33.643 回答