我正在使用一些代码(不是我的,我不得不添加,我根本不相信这一点)对于一个打开套接字,发出请求和侦听响应的类,这会以一种我可以的方式抛出异常在xunit中测试时要理解.我假设同样的异常发生在"实时"但是该类由单例引用,因此它可能只是隐藏.
问题在xunit中显示为"System.CannotUnloadAppDomainException:在卸载appdomain时出错",并且在关闭套接字时,内部异常是"System.ObjectDisposedException"抛出(基本上)在终结器内!在Socket类中没有其他引用调用close和dispose受保护的套接字,所以我不清楚该对象是如何处置的.
此外,如果我只是捕获并吸收ObjectDisposedException,则当xunit命中该行以关闭侦听器线程时,xunit会终止.
我只是不知道Socket在被要求关闭之前是如何处理的.
我对套接字的了解只是我从发现这个问题以来所学到的,所以我不知道我是否提供了所需的一切.LMK如果没有!
public class Foo { private Socket sock = null; private Thread tListenerThread = null private bool bInitialised; private Object InitLock = null; private Object DeInitLock = null; public Foo() { bInitialised = false; InitLock = new Object(); DeInitLock = new Object(); } public bool initialise() { if (null == InitLock) return false; lock (InitLock) { if (bInitialised) return false; sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); sock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 8); sock.Bind( /*localIpEndPoint*/); sock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(mcIP)); tListenerThread = new Thread(new ThreadStart(listener)); tListenerThread.Start(); bInitialised = true; return true; } } ~Foo() { if (bInitialised) deInitialise(); } private void deInitialise() { if (null == DeInitLock) return; lock (DeInitLock) { if (bInitialised) { sock.Shutdown(SocketShutdown.Both); //throws System.ObjectDisposedException sock.Close(); tListenerThread.Abort(); //terminates xunit test! tListenerThread = null; sock = null; bInitialised = false; } } } }
Jon Skeet.. 8
如果此对象符合垃圾回收条件并且没有其他对Socket的引用,那么套接字的终结器可能会在对象的终结器之前运行.我怀疑这就是发生在这里的事情.
在终结器中做这么多工作通常是一个坏主意(IMO).我记不起上次实现终结器了 - 如果你实现了IDisposable,你应该没问题,除非你直接引用非托管资源,这几乎总是以IntPtrs的形式.有序关闭应该是常态 - 如果程序正在关闭,或者有人忘记处理实例,那么终结器通常只应该运行.
(我知道你在开始时澄清说这不是你的代码 - 我只是想我会解释为什么它会有问题.如果你已经知道了部分/全部内容,请道歉.)
如果此对象符合垃圾回收条件并且没有其他对Socket的引用,那么套接字的终结器可能会在对象的终结器之前运行.我怀疑这就是发生在这里的事情.
在终结器中做这么多工作通常是一个坏主意(IMO).我记不起上次实现终结器了 - 如果你实现了IDisposable,你应该没问题,除非你直接引用非托管资源,这几乎总是以IntPtrs的形式.有序关闭应该是常态 - 如果程序正在关闭,或者有人忘记处理实例,那么终结器通常只应该运行.
(我知道你在开始时澄清说这不是你的代码 - 我只是想我会解释为什么它会有问题.如果你已经知道了部分/全部内容,请道歉.)