我一直在努力增加对垃圾收集的理解,管理&非托管资源,以及适当的设计原则"关于内存管理,因为我有兴趣进入"较低级别"编程和那种性质的东西。
我了解您假设使用using
阻止或其他一些解决方案来确保这些非托管资源实际上已被处理,但我不明白发生了什么事情。
我在MSDN上查看了这篇文章:Implementing a Dispose Method,并对此特定行感到困惑:
为了确保始终适当地清理资源,Dispose方法应该可以多次调用,而不会抛出异常。
让我们看一下它们为dispose模式提供的示例代码:
class DerivedClass : BaseClass
{
// Flag: Has Dispose already been called?
bool disposed = false;
// Instantiate a SafeHandle instance.
SafeHandle handle = new SafeFileHandle(IntPtr.Zero, true);
// Protected implementation of Dispose pattern.
protected override void Dispose(bool disposing)
{
if (disposed)
return;
if (disposing)
{
handle.Dispose();
// Free any other managed objects here.
}
// Free any unmanaged objects here.
disposed = true;
// Call base class implementation.
base.Dispose(disposing);
}
}
我相信上面引用的文字基本上是说什么,"我们添加了bool disposed
属性,以便我们检查true
{{1} }和return
如果是这样的话。如果是false
,那么我们会处理实际资源。这样我们就不会多次 多次处理某些事情"
但这对我没有意义。如果我们已经摆脱了某个对象,你怎么能再次打电话给Dispose
?
为了调查,我编写了一个包含以下3行的控制台应用程序:
var cmd = new SqlCommand();
cmd.Dispose();
cmd.Dispose();
这个编译和执行没有问题 - 这是有道理的,考虑到文章中的引用文本。但我不明白实际发生了什么
。我设置断点并跨过每一行。调用第一个Dispose
后,我希望Visual Studio中的Locals窗口告诉我cmd
是null
。按照这一思路我问自己,"你如何在Dispose
上致电null
?"显然,你不能。那么发生了什么?为什么cmd
在第一次处理后仍然是SqlCommand
个对象?
Dispose
做了什么完全,如果我处理了我的对象,为什么它似乎仍然存在于所有意图和目的?
为什么/以下如何编译和运行没有问题?
var cmd = new SqlCommand();
cmd.Dispose();
cmd.CommandText = "I figured this would throw an exception but it doesn't";
答案 0 :(得分:2)
IDisposable
接口由几个消耗类调用,并且 - 正如Dark Falcon已经说明的那样 - 当你将类的用法封装在using块中时。这样可以更轻松地保持非托管资源的清洁。
但Dispose
就像任何其他方法一样,不要与析构函数/终结符混淆(这是你显然预期的那样)
答案 1 :(得分:1)
除Dispose
语句可以为您调用之外,using
没有什么特别之处。除此之外,它就像任何其他.NET函数一样。它没有神奇地将任何变量设置为null
,导致在再次使用该对象时抛出异常,或者类似的任何变量。
同样,IDisposable
不是一个特殊的接口,除了using
语句中的对象必须实现它。你可以认为using语句是这样的:
// using(var a = somethingDisposable()) {otherCode();}
var a = somethingDisposable();
try
{
otherCode();
}
finally
{
if(a != null)
((IDisposable)a).Dispose();
}