Okay, now in terms of Native Resource Management and the partnership between you
as a manage programer and the CLR what I'm going to illustrate
on this slide is an example of a class called widget again.
This time know that the class, the manage class here is not using a COM component,
it's using a Win32-- some Win32 functionality directly
and what I've illustrated is actually P/Invoke declaration this is really, this is not accurate
but there really is a function of Win32 called create file mapping
and what it returns is a handle to a kernel object
and I've definitely not accurately represented it's parameter list here so don't try
to use this declaration as it is but the idea is that it can return a handle to a kernel object
that represents in memory mapping of a particular file out in the file system
and as such because it's a kernel object handled that's been return to you any programmer
who calls create file mapping has to always make sure that they make the corresponding call
to CloseHandle to reduce the reference count on the underline kernel object
and if this was the last call to CloseHandle actually forget the memory associated
with that kernel object.
So, what I've got here is I manage class that then uses that P/Invoke declaration
to allocate the underlined kernel object and get back a handle.
And so this is typically stored and manage code as an int pointer that's a standard structure
to find by the FCL and then as before in the previous COM base demo I also have a handle
to appear managed object called System.io.stream and I just want to show you how we're going
to deal with these two very different creatures in terms of finalization and disposal, okay.
So, the first step is that I need to because I'm directly interacting with a Win32 resource.
I need to be myself a finalizable type because although I've implemented IDispose
that doesn't mean that my clients are required to call my dispose method
and so the idea behind finalization is that if my clients do not call dispose
and give me a chance to call CloseHandle on this final mapping handle I still need
to call CloseHandle even in that circumstance because if I don't I'm going
to leak some memory, I'm going to-- I'm going to leak for the duration of my process
that I've been loaded in I'm going to leak that file mapping object.
And so, finalization in C# is indicated by using this TLD syntax to tell my compiler,
"I need you to override System.Object.Finalize as a virtual function."
I've got access too from my base class and during the garbage collection process
when the CLR has decided that there are no more reference system widget and it's safe
to reclaim the memory associated with that widget, when it gets to that point,
it will go ahead and contrive or conspire to call my Finalizer method and I can use
that as sort of a last gasp measure to make sure that even
if the managed client using my widget does not call IDisposable.Dispose, I can still pull off
or call the CloseHandle and let go of that underlying native resource.
So that's sort of the first level step.
That's really important.
Second level is that if my client does call IDisposable.Dispose, well then I'd go ahead
and release that native resource like we should before in the COM case.
I also chain my call to Dispose on to any embedded or referenced, you know,
objects that I am holding references to.
So I'm going to go ahead and call Dispose on that stream and then this is really important.
Since I have taken care of the early cleanup of the native resource,
I no longer need the Finalizer thread to call my Finalizer method and so,
we use GC.SuppressFinalize passing in the object reference associated with our widget here
to tell the CLR, "You know, I don't need you to call that finalization method.
I don't need you to call this method down the road.
I've taken care of everything I need to take care of."
So this is an optimization.
It's not technically required but if you don't do this, it's really important that you beef
up the logic here so that you don't attempt to call CloseHandle multiple times
but doing this is very useful because it allows the CLR to forgo that second step process
of setting it up so that when it's ready to reclaim your memory, it has to hold off
until it's had a chance to finalize you and so, this can help with the overall usage of memory
and your managed heap and it's a very, very good idea to do.