I have a problem I cannot seem to figure out, please help. I have created a class to handle an interface to some HW using TcpClient. I want this class to send one last command to the HW before it is destroyed.
To solve this I have implemented IDisposable.Dispose to take care of the sending of the last command and then close the connection. I have also in the destructor made a call to Dispose. This is the Microsoft recommendation as I read it in this article. My code is as follows:
class MyHWInterface : IDisposable
{
~MyHWInterface()
{
Dispose();
}
private bool disposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
CloseConnection();
disposed = true;
}
}
private System.Net.Sockets.TcpClient Port = new System.Net.Sockets.TcpClient();
public bool OpenConnection()
{
...
}
private bool SendCommand(string command)
{
var strm = Port.GetStream(); // This throws the exception Cannot access disposed object!
var w = new System.IO.StreamWriter(strm, System.Text.Encoding.ASCII);
var r = new System.IO.StreamReader(strm, System.Text.Encoding.ASCII);
w.WriteLine(command);
w.Flush();
string l = r.ReadLine();
return l == "OK";
}
internal void CloseConnection()
{
try
{
SendCommand("power down now");
}
catch
{
}
finally
{
Port.Close();
}
}
}
My problem is: When my program ends, and my object of MyHWInterface therefore falls out of scope and then gets garbage collected. The destructor is called which tries to send the last command, which fails because somehow my TcpClient is already disposed.
Please tell me why an object which is clearly not yet out of scope is being disposed. And please help with a method that makes sure my last command always will be send without an explicit call to Dispose.
Please tell me why an object which is clearly not yet out of scope is being disposed.
Objects don't have a concept of "scope" as such. At the end of your program, both the TcpClient
and the instance of your class are eligible for finalization - and there's no guarantee which will be finalized first. It sounds like the TcpClient
is being finalized (and the connection closed) first, hence the issue.
The best fix is not to rely on finalization for this in the first place - remove your own finalizer (realizing that the connection will just be closed at some point if the client doesn't call Dispose
) and make sure that you do dispose of everything in an orderly fashion when your program terminates, assuming it's terminated cleanly (i.e. through some path you control).
See more on this question at Stackoverflow