变量= null作为"对象破坏"来自何处?

Pau*_*ner 22 .net c# design-patterns anti-patterns

我在不同的公司中使用不同版本的.NET编写的许多遗留系统,我不断寻找以下模式的示例:

public void FooBar()
{
    object foo = null;
    object bar = null;

    try
    {
       foo = new object();
       bar = new object();

       // Code which throws exception.
    }
    finally
    {
       // Destroying objects
       foo = null;
       bar = null;
    }

}
Run Code Online (Sandbox Code Playgroud)

对于任何知道内存管理在.NET中如何工作的人来说,这种代码是非常不必要的; 垃圾收集器不需要您手动分配null以告知可以收集旧对象,也不需要分配null指示GC立即收集对象.

这种模式只是噪声,使得理解代码试图实现的内容变得更加困难.

那么,为什么我一直在寻找这种模式呢?是否有一所学校教授这种做法?是否有一种语言,null需要为本地范围的变量赋值才能正确管理内存?明确指定null我还没有得到一些额外的价值吗?

Aar*_*lla 22

这是FUD 货物狂热编程(感谢Daniel Earwicker),他们习惯于"释放"资源,糟糕的GC实现和糟糕的API.

一些GC没有很好地处理循环引用.要摆脱它们,你必须"在某个地方"打破这个循环.哪里?好吧,如果有疑问,那么无处不在.这样做了一年,它已经移动到你的指尖.

同时设置字段可以null让您了解"做某事",因为作为开发人员,我们总是担心"忘记某些事情".

最后,我们必须明确关闭API,因为没有真正的语言支持来说"当我完成它时关闭它"并让计算机像GC一样解决它.所以你有一个API,你必须在那里调用清理代码和API.这会吸引并鼓励上述模式.

  • 感谢循环引用的提示,这实际上是在旧的VB和类似的引用计数系统中手动置换变量的最可能的解释. (2认同)
  • 拥有必须明确清理的对象的这项业务让我想起了"IDisposable".虽然我想用一个实现`IDisposable`的对象,你最好把它称为`Dispose()`方法. (2认同)
  • 调用`Dispose`当然是可选的.如果你不这样做,GC会有效地为你做,而不是你想要它.当你的一次性物品没有离开你的范围时,`使用'只是正确的做法.有关反例,请参阅Rx的`IObservable.Subscribe`. (2认同)

Bri*_*eon 8

它可能来自VB,它使用引用计数策略进行内存管理和对象生存期.将引用设置为Nothing(等效于null)将减少引用计数.一旦该计数变为零,则该对象被同步销毁.离开方法的范围后,计数将自动递减,因此即使在VB中,这种技术大多无用,但是在某些特殊情况下,您可能希望贪婪地销毁对象,如下面的代码所示.

Public Sub Main()
  Dim big As Variant
  Set big = GetReallyBigObject()
  Call big.DoSomething
  Set big = Nothing
  Call TimeConsumingOperation
  Call ConsumeMoreMemory
End Sub
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,引用的对象big将一直徘徊到没有调用的结尾Set big = Nothing.如果该方法中的其他内容是耗时的操作或产生更多的内存压力,那么这可能是不合需要的.

  • 我在当天做了一些VB6和VB4编程,并且当你完成它们时将对象设置为null的建议是无处不在,特别是对于通过ADO或DAO的数据库连接.坦率地说,我认为有一种情况需要它,许多其他开发人员通过迷信采用这种做法,而不是理解你可能会这样做的原因.也就是说,在VB6中,我确实发现当两个对象形成一个循环引用时,有时我必须这样做.VB并不总是正确地拆掉这些结构并且可能会泄漏内存. (3认同)