I hope my answer would be clear
-) If I add a delegate handler to a class, do I have to unplug it before
destroying the class for GC to work correctly?
1you don't destroy the instance your self (it's GC responsability), if you
call dispose you will just create problem if the object is still referenced
in a live oject through an event delegate.
yep you need to unplug it to collect it, do that in Dispose()
.
You do well to see that, many people don't.
-) Who actually calls Destroy if I implement IDisposable?
Dispose() you mean?
it's your responsability!
althought
using(Blabla bla= new Blabla())
statetment;
would call Dispose() automatically for you if it can be.
-) What is the difference between Destroy() and Destroy(bool) and who
calls each implementation and when?
Dispose(bool) is usually called by Dispose().
why do they use such convoluted apporach?
it's a bit subtle and it's related to unmanaged resource, somewhere in the
SDK it's well explained but I can't find it again.
shortly:
- managed memory is automaticall managed!
- however unmanaged resource (typically resource acquire through interop
with win32) are not
- also some classes use some sparse or huge system resource and you want to
have a way to release them explicitely soon
- object are first marked for deletion, then deleted in random order,
therefore you should'nt call method on your managed properties while being
disposed (if dispose as been call from the destructor)
the pattern is the following:
if you have unmanaged resource, release them in Dispose() and ensure dispose
is called by overriding the destructor:
class MyClass : IDisposable
{
IntPtr unmanagedresource;
public MyClass() {}
~MyClass() { Dispose(); } //<=otherwise dispose won;'t be automatically
called!
public void Dispose()
{
GC.UnregisterFinalize(this);
if(unmanagedresource != IntPtr.Zero)
{
FreeUnmanagedResource(unmanagedresource);
unmanagedresource = IntPtr.Zero;
}
}
}
however a problem arise if you've got manage resource as well.
class MyClass : IDisposable
{
IntPtr unmanagedresource;
OtherClass managedresource;
public MyClass() {}
~MyClass() { Dispose(); }
public void Dispose()
{
GC.UnregisterFinalize(this);
if(unmanagedresource != IntPtr.Zero)
{
FreeUnmanagedResource(unmanagedresource);
unmanagedresource = IntPtr.Zero;
}
managedresource.SomeMethod(); // <== potential problem
}
}
the problem is if Dispose() was called by ~MyClass() your managedresource
could have already been freed, which would led to an exception!
hence the following pattern:
class MyClass : IDisposable
{
IntPtr unmanagedresource;
OtherClass managedresource;
public MyClass() {}
~MyClass() { Dispose(false); }
public void Dispose() { Dispose(true); }
protected virtual void Dispose(bool disposing)
{
if(unmanagedresource != IntPtr.Zero)
{
FreeUnmanagedResource(unmanagedresource);
unmanagedresource = IntPtr.Zero;
}
if(disposing)
{
GC.UnregisterFinalize(this);
managedresource.SomeMethod();
}
}
}
-) Is it worth setting expired (variables I won't use again in a function)
variables to null to aid GC? no
-) Can I or should I aid GC by using 'using' constructs or won't this help
if objects don't implement IDisposable?
it helps only with IDisposable
Any help would be appreciated.
you're wellcome