我正在努力确保我的理解IDisposable是正确的,并且我仍然不太确定.
IDisposable 似乎有两个目的.
我的困惑来自于确定哪些场景具有"非托管资源".
假设您使用的是Microsoft提供的IDisposable实现(托管)类(例如,数据库或套接字相关).
IDisposable仅仅在1或1和2以上实现?问题是,如何在调用finalize时测试对象配置资源的事实。该类的代码:
public class TestClass : IDisposable {
public bool HasBeenDisposed {get; private set; }
public void Dispose() {
HasBeenDisposed = true;
}
~TestClass() {
Dispose();
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,我现在不关心正确的Dispose / Finalize实现,因为我想首先找到对其进行测试的方法。在此阶段,如果调用了Dispose / Finalize软件,就可以假设将HasBeenDisposed设置为true。
我写的实际测试看起来像:用
WEAKREFERENCE更新:
[Test]
public void IsCleanedUpOnGarbadgeCollection() {
var o = new TestClass();
o.HasBeenDisposed.Should().Be.False();
**var weak = new WeakReference(o, true); // true =Track after finalisation
o = null; // Make eligible for GC**
GC.Collect(0, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
**((TestClass)weak.Target)**.HasBeenDisposed.Should().Be.True();
}
Run Code Online (Sandbox Code Playgroud)
或我更喜欢的代码(ADDED AFTER UPDATE):
[Test]
public …Run Code Online (Sandbox Code Playgroud) 如果在执行finalize()期间抛出异常会发生什么?堆栈是否正常放松?它是否继续finalize()并忽略该异常?它是否会停止finalize()并继续GC对象?或者是其他东西?
我不是在寻找使用finalize()的指导方针.有很多页面解释了这一点.
我在C#中有一个类,我想在我的课程处理时正确地关闭一些通信端口.但是,退出程序时永远不会调用终结器.这是为什么?难道我做错了什么?
我正在手动调用dispose,它会通过并关闭所有通信.这也没有解雇.
这是我正在使用的终结器:
~Power()
{
Dispose(false);
}
Run Code Online (Sandbox Code Playgroud) 我已经看过提到这个特定异常的各种问题(这个问题列出了很多,我访问过的).此外,我有与本文相同的一般性问题,但在不同的背景下,所以答案对我没有帮助.
上下文
我有一个派生自AxWindowsMediaPlayer的类View,由一个名为的类所拥有,该类Panel位于a中Workspace.我最近问了一个关于这种情况的问题,但是这个问题是针对这个问题的解决方法是否合适.该问题的背景与此相关:
.-----------------------.
|Workspace |
|.--------. .--------. |
||Panel1 | |Panel2 | |
||.-----. | |.-----. | |
|||View1| | ||View2| | |
||'-----' | |'-----' | |
|'--------' '--------' |
'-----------------------'
当一个View被释放时,一个被调用的方法Synchronize()将被调用所有剩余的View对象.对于View那个包含的AxWindowsMediaPlayer,它调用videoPlayer.Error.clearErrorQueue().
问题
当我Dispose()在顶级(Workspace.Dispose())调用时,如果另一个View被调配,然后导致Synchronize()在剩余的View对象上调用,则View包含 …
当看到整个 finalizer/IDisposable 问题时,通常会看到,在所有冗长的描述之后,最后都会有“哈哈,我说的实际上没用,你应该使用 SafeHandle 代替再见”的意思!” 所以我想知道在什么情况下 SafeHandle 不适合,以至于你不得不求助于终结器/IDisposable 旧方法?
我有这个代码:
基本上我正在尝试演示使用c#终结器并制作一个不能死的对象,我称之为Zombie.现在,通常这个演示工作得很好,但今天我尝试使用与对象初始化器相同的代码而不是仅仅分配给属性(在这种情况下为Name).我注意到有区别.即使终结器永远不会被调用,即使我正在尽最大努力使垃圾收集器完成它的工作.
有人可以解释这个区别,还是我在C#编译器中发现了一个错误?
(我在Win7x64上使用VS2010 SP1中的C#4)
谢谢.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace Zombie
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Main thread: " + Thread.CurrentThread.ManagedThreadId);
// case 1: this is where the problem is located.
Zombie z = new Zombie { Name = "Guy" }; // object initializer syntax makes that the finalizer is not called.
// case 2: this is not causing a problem. The finalizer gets called.
//Zombie z = new …Run Code Online (Sandbox Code Playgroud) 假设我已经使用close()方法创建了一些用于清理资源的资源类,并且如果有人忘记调用close(),我想覆盖finalize()以释放资源(并打印警告).怎么能正确完成?
注意:我知道使用finalize()通常是个坏主意,并且不能保证被调用,还有其他一些问题在讨论这个问题.这个问题具体是关于如何在Java中实现终结器,而不是为什么你应该(或不应该).
在Headfirst C#一书中,我认为"在终结器中序列化一个对象并不是一个好主意,因为序列化需要整个对象树在堆中,但是你可能最终缺少重要部分你的程序是因为在终结器运行之前可能已经收集了一些对象."
我的问题是,由于我的对象获得了对其他对象的引用(这意味着至少有一个对其他对象的引用),在终结器运行之前它们如何被垃圾收集?
我知道垃圾收集器使用Finalize方法让对象释放非托管资源.根据我所知,Object.Finalize永远不会被GC直接调用(如果它的类型通过实现终结器来覆盖 Finalize方法,则在构造过程中将对象添加到f-reachable队列中).
Object.Finalize仅从自动生成的终结器代码中调用:
try
{
//My class finalize implementation
}
finally
{
base.Finalize(); // Here chain of base calls will eventually reach Object.Finalize/
}
Run Code Online (Sandbox Code Playgroud)
因此,从Object派生一个任意类,不会调用Object.Finalize - 你需要对Object.Finalize的终结器有意义,对于大多数类来说它没有意义并且没有使用(不是说它的实现是空的).
如果没有覆盖Object.Finalize,并且在没有try {} finally { base.Finalize() }调用的情况下生成根终结器,那么在类中检查Finalize方法的存在是否太复杂?类似于Add集合初始化的方法 - 您不必实现任何接口或覆盖该方法 - 只需实现public void Add(item)方法.
它会使C#编译器有点复杂,但是通过删除一个冗余调用使得终结器运行得稍微快一些,最重要的是 - 使得Object类更容易理解而不需要具有Finalize空实现的保护方法,而不需要完成任何事情.
此外,有可能实现从Object派生的FinalizableObject类,并使编译器派生所有具有终结器的类.它可以实现IDisposable并使得Microsoft推荐的处理模式可以重用,而无需在每个类中实现它.其实我很惊讶这样的基类不存在.