2012-06-15 104 views
4

我试图提高FxCop在我的代码中的符合性(这是有史以来的第一次),但我有点卡在道德问题上。我有一个方法GetText()从远程服务器返回一个字符串,但可以在某些情况下抛出异常。这就是为什么我也有一个方法TryGetText(ByRef text As String)返回一个布尔值,它表示调用是否成功。如果为true,则将返回值分配给文本变量。'TryAction()'方法是否邪恶?

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

回答

0

嗯,我想每个人都恨太多byrefs。两个已经太多了。虽然在你的情况下有很多方法,他们都遵循相同的模式听起来不是一个真正的问题。 您可以选择不拘泥于Microsoft的Try *方法模式。

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

这确实是更多的代码,但它确实解决了警告(如果那真的是你以后的话)。

+1

我可能已经做了这样的事情,但空(或空)(或者甚至是空白)都是可能的返回值。只有当服务器拒绝返回文本时,调用才会失败。我的代码需要知道它是否失败,或者服务器是否返回空字符串。 –

+0

然后,您最好使用byref和SuppressMessageAttribute。无论是这样或者你可以通过将你的响应包装在一些可以告诉你操作状态的东西中,使得事情复杂化,除了实际的字符串结果。 –

+0

我猜通过使用这些所谓的元组?我应该仔细研究一下。我不认为我以前曾经使用过一个元组...... –

2

这可能是一个很好的使用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在Concurrent集合类中大量使用它。例如http://msdn.microsoft.com/en-us/library/dd287191.aspx#Y0

所以我想一个总括性的声明“你不能通过引用传递。”在任何情况下都不应该被视为福音。有合法的用途。在你的具体情况下,ByRef似乎比StringBuilder版本笨拙得多。但是如果一个简单的string GetText()返回null/Nothing,如果你当前返回false是等价的,那看起来最好。

+0

我不能让它在这种情况下返回null,因为null对于我正在做的事来说是一个有效的值。所以我想这证实了它是正确使用ByRef。 –

+0

+1这些规则是好仆人,但不好主人。他们不应该盲目服从。 – MarkJ

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() { 
    ... 
} 
+0

你可以在C#中创建可为空的字符串吗?我检查确认,但它不让我在VB中(尽管该字符串的行为像其他方式的值类型)。 –

+0

不,你不能,因为一个字符串已经是一个对象。但是,如上所述,您可以直接返回null。我的答案应该是:为值类型使用可为空的类型;对于引用类型,返回null。然而,“干净”的方式可能是Option类,因为许多功能语言都是这样做的。 – JohnB