Reputation: 2146
I'm using a 3rd party assembly to provide sftp functionality to my project as shown below. Multiple threads need to implement this functionality so the 3rd party assembly is consumed in a static helper class.
The 3rd party assembly works well unless an unusual error condition is encountered, e.g. the sftp server exists but the directory I'm attempting to put files into gets deleted. When this happens a valid exception is thrown however it appears that intermittently the 3rd part assembly isn't cleaning up after itself correctly as no new instances of the client will work.
static readonly object _locker = new object();
static void WorkerMethodCalledByThread()
{
lock(_locker)
{
var client = new ThirdPartyAssembly();
bool hasConnection = false;
try
{
client.Connect("some connection details");
hasConnection = true;
// do some work -
//but if an issue happens here then no new instances of ThirdPartAssembly work
}
catch(Exception e)
{
Logger.LogError(e);
}
finally
{
if (hasConnection) { client.Close(); }
}
}
}
I have no means to get the 3rd party assembly changed so what I'm looking for is a way to dispose of any resources it may have taken. However the 3rd party class being called does not implement IDisposable itself.
So.. I'm trying to figure out if its possible to release the resources used by the 3rd party ?
The two possible approaches I can think of are either
1: add a wrapper class which has the 3rd party class as its base class & which also implements IDisposable (shown below) - however I'm pretty sure this won't clean up the base class
2: use a WeakReference to the 3rd party class (shown below) - but I don't know if this will work
Wrapper Class
public class WrapperClass : ThirdPartyClass, IDisposable
{
~WrapperClass()
{
Dispose();
}
public void Dispose()
{
GC.SuppressFinalize(this);
}
}
WeakReference
static readonly object _locker = new object();
static void WorkerMethodCalledByThread()
{
lock(_locker)
{
var client = new WeakReference(new ThirdPartyAssembly());
bool hasConnection = false;
try
{
((ThirdPartyAssembly)client.Target).Connect("some connection details");
hasConnection = true;
// do some work -
//but if an issue happens here then no new instances of ThirdPartAssembly work
}
catch(Exception e)
{
Logger.LogError(e);
}
finally
{
if (hasConnection) { ((ThirdPartyAssembly)client.Target).Close(); }
}
}
}
Upvotes: 1
Views: 362
Reputation: 67898
So the problem with the WeakReference
is:
while still allowing that object to be reclaimed by garbage collection.
it doesn't guarantee that GC will get to it because it clearly isn't managing itself well internally.
The better approach is to base the class and implement IDisposable
. This will allow you to leverage your wrapper in a using
statement. However, the caveat is this, and there's really no way around it, you're going to have to use Reflection
to dig into this class and clean it up.
It's going to take a lot of breakpoints, and a lot of digging in the Watch
windows, but you can get it done!
Upvotes: 1