我正在努力改进我的代码中的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变种也改善了代码的可用性。
答案 0 :(得分:2)
这可能是ByRef
的好用,所以我倾向于为该案例添加例外。如果您在Visual Studio中使用代码分析功能,则只需将以下属性添加到方法中即可:
<System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", MessageId = "1#")> _
Public Function TryGetText(ByRef text As String) As Boolean
答案 1 :(得分:2)
在创建线程安全类之类的东西时,TryAction方法非常有用。它将两个步骤(测试和操作)组合成单个原子操作。 Microsoft在Concurrent集合类中大量使用它。例如http://msdn.microsoft.com/en-us/library/dd287191.aspx#Y0
所以我认为“你不能通过引用传递”的一揽子声明。在所有情况下都不应被视为福音。有合法用途。在您的特定情况下,ByRef似乎比StringBuilder版本更不笨拙。但是如果在当前返回false的情况下返回null / Nothing的简单string GetText()
是等效的,那么这似乎是最好的。
答案 2 :(得分:0)
嗯,我想每个人都讨厌过多的反对意见。两个已经太多了。虽然在你的情况下有很多方法,他们都遵循相同的模式听起来不是一个真正的问题。 您可以选择不遵守Microsoft的Try *方法模式。
而不是布尔值,为什么不在成功时返回字符串,如果失败则返回Nothing / Empty? 然后,您可以使用String.IsNullOrEmpty(resultText)测试TryGetText输出。
确实,这是更多的代码,但它确实解决了警告(如果这真的是你所追求的那样)。
答案 3 :(得分:0)
当您尝试在功能样式中使用方法时,通过引用传递会使事情变得复杂。您可以考虑使用可空类型或元组或您自己的选项类型。
由于我不熟悉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 () {
...
}