【问题标题】:vb.net syntax using stringbuilder in function在函数中使用 stringbuilder 的 vb.net 语法
【发布时间】:2024-06-24 17:15:02
【问题描述】:

在返回字符串的函数中使用 stringbuilder 时,正确的代码语法是什么(在函数末尾将 StringBuilder 实例设置为 Nothing)? 通常我会尝试使用语句“使用”,但 StringBuilder 不实现 iDisposable。

更准确地说:我想在 GC 运行时释放 StringBuilder 实例占用的内存,所以我想在 Function 结束时将 StringBuilder 实例设置为 Nothing。

请问有人知道我应该在哪里将 StringBuilder 实例设置为 Nothing?

这是代码。

Function GetString() As String
    Try()
        Dim sb As New StringBuilder
        sb.AppendLine("my first line")
        Return sb.ToString()
        'Should i put here 'sb = Nothing' ?
    Catch()
        Return Nothing
    End Try()
End Function

或者这个解决方案更好?

Function GetString() As String
    Dim sb As New StringBuilder
    Try()
        sb.AppendLine("my first line")
        Return sb.ToString()
    Catch()
        Return Nothing
    End Try()
    'Or should i put here 'sb = Nothing' ?
End Function

【问题讨论】:

  • 您不需要将 StringBuilder 设置为空,.net 垃圾收集器将处理所有必要的事情。为什么你认为你需要这样做?您似乎已经知道,当一个类实现 IDisposable 时,您需要担心这一点并使用 using-block。
  • @Esko 但是 StringBuilder 没有实现可丢弃的。所以我不能写“使用 sb 作为新的 StringBuilder”。为什么你说我不需要将 StringBuilder 设置为 Nothing?在不等待 GC 的情况下销毁所有不再使用的变量不是一个好习惯吗?
  • 没有所谓的“破坏变量”。如果一个类型实现了IDisposable 接口,那么你应该在处理完该类型的对象后释放它们。如果您只在定义的范围内使用它们,Using 块是最好的方法。如果一个类型没有实现IDisposable,那么就没有什么可以“破坏”了。您可以将变量设置为Nothing 以使其引用的对象更快地可用于垃圾回收,但是,如果变量立即超出范围,那将毫无意义。只清除一段时间后将在范围内的变量。
  • @jmcilhinney 抱歉,摧毁我的意思是把它设置为 Nothing。那么在示例中,您将在哪里将 StringBuilder 设置为 Nothing?为什么?
  • 就像我之前所说的,这是一个范围界定的问题。一旦变量超出范围(调用 Return),它就会从堆栈中弹出并删除引用。如果你不能等待范围退出,你可能需要重构你的代码。您给出的示例相对简单,但是如果碰巧该方法更长并且做了更多的事情,您可以简单地将它们分解为更小的方法,从而管理声明的变量的范围。除此之外,没有办法将变量设置为 Nothing after 您已经调用了 Return。很明显,你不能在之前设置它。

标签: vb.net function stringbuilder


【解决方案1】:

我在 c# 中编写了相同的函数,在您的情况下,没有必要清理“stringbuilder”变量,但是,为了在 return 语句之后确保清理,您可以使用 try...finally 块。

static string GetString()
{
     StringBuilder sb = new StringBuilder();
     try
     {
          sb.AppendLine("myfirstline");
          return sb.ToString();
     }
     finally
     {
          sb = null;
     }
}

【讨论】:

  • 非常感谢您的帮助,bdn02。我认为因为我在 Try-Catch 块“外部”声明了 StringBuilder 实例,所以我可以在 Try-Block Catch 之外也将其设置为 Nothing。我认为最佳实践会将其设置为 Nothing,就像我在第二个示例中所写的那样(Try-Catch 之外)。
  • 不,最佳做法是将其设置为 Nothing。正如您一遍又一遍地被告知的那样,将该变量设置为Nothing 是没有意义的,因为该变量本身在之后立即不再存在。将变量设置为Nothing 的唯一原因是该变量本身是否会在范围内保留很长时间,从而阻止垃圾收集器最终确定它所引用的对象。如果变量超出范围,则对该对象的引用不再存在,因此效果是相同的。将变量设置为Nothing 是没有意义的。做无意义的事情是不好的做法。
  • @jmcilhinney 谢谢,你是对的,现在我明白了。 GC 会尽快处理未使用的方法,因此局部变量占用的内存会被快速释放。感谢您的宝贵帮助。
【解决方案2】:

好的,感谢一些花费大量时间帮助我学习的用户(@jmcilhinney、@Anu6is),我发布了我的答案。

在方法中释放本地资源的正确语法是这样的:

Function GetString() As String
    Try()
        Dim sb As New StringBuilder
        sb.AppendLine("my first line")
        Return sb.ToString()
    Catch()
        Return Nothing
    Finally()
        'N.B. Good practice don't write
        'sb = Nothing
    End Try()
End Function

请注意,在最后的声明中,我写了“良好实践”以不写

sb = Nothing

为什么? 因为方法内部的每一个局部变量,当代码执行退出方法时,都会被垃圾收集器自动“清理”(GC会释放之前被局部变量占用的内存,但是如果代码的执行会使用再次在垃圾收集器运行之前的方法,之前占用的内存区域将由局部变量的新实例的指针重新分配。

不同的方法是当方法使用非局部变量时:

Class MyClass
    Dim sb As New StringBuilder

    Friend Function GetString(ByVal text as String()) As String
        Try()
            For Each Txt As String In text
                sb.AppendLine(Txt)
            Next Txt
            Return sb.ToString
        Catch()
            Return Nothing
        Finally()
            'Here i can write:
            'sb.Clear
            'or
            'sb = Nothing 
        End Try()
     End Function
 End Class

为什么在这种情况下将变量设置为 Nothing 或(在这种情况下)释放 StringBuilder 值占用的内存是一个好习惯?

可能是,例如,我在程序开始时使用该方法,而不是更多。

或者,如果 StringBuilder '存储'大量数据,需要很长时间。

在这种情况下,我们“选择”将 StringBuilder 设置为 Nothing,以释放占用的内存,该内存不会被程序使用。

这篇文章,很好地解释了在方法内部将变量设置为 Nothing 的情况。

https://blog.stephencleary.com/2010/02/q-should-i-set-variables-to-null-to.html

在这之后,可能会想到一个问题:

'但是如果我等待垃圾收集器将'释放'内存,我需要等待多长时间? ...滴答声...毫秒,...秒,...分钟...?

这里有一个可以提供帮助的链接:

https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals

【讨论】: