|
-
May 21st, 2009, 10:18 PM
#1
Thread Starter
Frenzied Member
When to use IDisposable?
Hello,
I have been working on this for a while now. And I am still confused about some issues. My questions below
1) I know that you only need a finalizer if you are disposing of unmanaged resources. However, if you are using managed resources that make calls to unmanaged resources. Would you still need to implement a finalizer?
2) However, if you develop a class that doesn't use any unmanged resources directly or indirectly and you implement the IDisposable so that clients of your class can use the 'using statement'. Would it be acceptable to implement the IDisposable just so that clients of your class can use the using statement?
Code:
myClass objClass = new myClass()
using objClass
'Do work here
End Using
3) I have developed this simple code below to demostrate the Finalize/dispose pattern:
Code:
Public Class NoGateway
Implements IDisposable
Private wc As WebClient = Nothing
Public Sub New()
wc = New WebClient()
Using wc
AddHandler wc.DownloadStringCompleted, AddressOf wc_DownloadStringCompleted
End Using
End Sub
' Start the Async call to find if NoGateway is true or false
Public Sub NoGatewayStatus()
' Start the Async's download
wc.DownloadStringAsync(New Uri(www.xxxx.xxx))
' Do other work here
End Sub
Private Sub wc_DownloadStringCompleted(ByVal sender As Object, ByVal e As DownloadStringCompletedEventArgs)
' Do work here
End Sub
' Dispose of the NoGateway object
Public Sub Dispose()
RemoveHandler wc.DownloadStringCompleted, AddressOf wc_DownloadStringCompleted
wc.Dispose()
GC.SuppressFinalize(Me)
End Sub
End Class
Question about the source code:
1) Here I have not added the finalizer. And normally the finalizer will be called by the GC, and the finalizer will call the Dispose. As I don't have the finalizer, when do I call the Dispose method? Is it the client of the class that has to call it?
2) I have added my RemoveHandler in the Dispose method. Is this the place I should be removing it?
3) I am using the 'using statement' to create the webclient. However, is this bad design as when the code executes at the end of the 'using statement' the webclient object will no longer exist?
4) I am using the webclient class in my 'NoGateway' class. Because the webclient implements the IDisposable interface. Does this mean that the webclient indirectly uses unmanaged resources? Is there any hard and fast rule to follow about this. How do I know that a class uses unmanaged resources?
5) Is my source correctly implementing the Finalize/Dispose pattern if the webclient is using unmanaged resources.
Sorry for the long list of questions here. However, just trying to get this 100% clear to me.
Many thanks,
-
May 21st, 2009, 10:33 PM
#2
Re: When to use IDisposable?
Your dispose sub includes you disposing wc, but you already disposed it in your using statement in the New sub.
Edit: Now I see your question #3. Yes, that object will be disposed after it adds that handler.
Last edited by ForumAccount; May 21st, 2009 at 10:36 PM.
-
May 21st, 2009, 10:37 PM
#3
Re: When to use IDisposable?
In truth, there really are only unmanaged resources. A managed resource is just a managed object that itself holds unmanaged resources, or holds a reference to another managed resource. If you have a managed object that has a reference to a managed object that has a reference to a managed object that holds an unmanaged resource then there's really only one resource, but all the managed objects are considered managed resources. Any and every managed resource must have a Dispose method. If a class has a Dispose method then it's a managed resource. If a class holds managed or unmanaged resources then it MUST have a Dispose method.
So, it's going to be relatively rare that your managed objects hold unmaanged resources directly, although it will happen sometimes. More likely is that you will have a reference to a managed resource, which is an indirect reference to an unmanaged resource.
Implementing the IDisposable interface is easy. You simply type "implements idisposable" under your class declaration and hit Enter:
vb.net Code:
Public Class NoGateway Implements IDisposable Private disposedValue As Boolean = False ' To detect redundant calls ' IDisposable Protected Overridable Sub Dispose(ByVal disposing As Boolean) If Not Me.disposedValue Then If disposing Then ' TODO: free other state (managed objects). End If ' TODO: free your own state (unmanaged objects). ' TODO: set large fields to null. End If Me.disposedValue = True End Sub #Region " IDisposable Support " ' This code added by Visual Basic to correctly implement the disposable pattern. Public Sub Dispose() Implements IDisposable.Dispose ' Do not change this code. Put cleanup code in Dispose(ByVal disposing As Boolean) above. Dispose(True) GC.SuppressFinalize(Me) End Sub #End Region End Class
You then simply replace the three TODOs with the appropriate code. If you have no managed resources then you can remove the first TODO, and therefore the If block too. If you have no unamanged resources you can remove the second TODO. If you have no large fields then you can remove the third TODO.
In your case you would replace the first TODO with your RemoveHandler and webClient.Dispose code. The second TODO would go and you could set your WebClient field to Nothing in place of the third if you wanted.
You are incorrectly using the Using statement in that code. The point of the Using block is to create an object that will be used only within that block and disposed at the End Using statement. Obviously that's not what you want.
-
May 21st, 2009, 11:08 PM
#4
Thread Starter
Frenzied Member
Re: When to use IDisposable?
Hello,
Sorry to be a pain, just a few questions about your comments.
I have made the adjustments to my code. I know VB does this, but I would like to do it myself, for my own understanding.
vb Code:
Public Class NoGateway Implements IDisposable Private wc As WebClient = Nothing Public Sub New() wc = New WebClient() AddHandler wc.DownloadStringCompleted, AddressOf wc_DownloadStringCompleted End Sub ' Start the Async call to find if NoGateway is true or false Public Sub NoGatewayStatus() ' Start the Async's download wc.DownloadStringAsync(New Uri([url]www.xxxx.xxx[/url])) ' Do other work here End Sub Private Sub wc_DownloadStringCompleted(ByVal sender As Object, ByVal e As DownloadStringCompletedEventArgs) ' Do work here End Sub ' Dispose of the NoGateway object Public Sub Dispose() RemoveHandler wc.DownloadStringCompleted, AddressOf wc_DownloadStringCompleted wc.Dispose() wc = Nothing End Sub End Class
As I am not using any unmanaged resources I have removed the if statement and the boolean, and also the GC.SuppreseFinalizer() as I don't have a finalizer that the GC will call.
So when the client of this class it using it I could do 2 things that will call the Dispose()
1)
objNoGateway = new NoGateway()
Using objNoGateway
' Use the object and when it reaches the end of the using statement it will automatically call the Dispose method
End Using
2) Manually dispose of the object
objNoGateway = new NoGateway()
' use the object and when finished call the dispose method
objNoGateway.Dispose()
As my NoGateway wraps the WebClient class. I don't need to dispose of my NoGateway class as that is handled by the framework?
Many thanks,
-
May 21st, 2009, 11:34 PM
#5
Re: When to use IDisposable?
You should absolutely NOT write out all the code yourself because you're actually making it harder to understand. Have you tried to compile that code? It will refuse and it will tell you that your class has no implementation for the IDisposable.Dispose method. That's because you have failed to add the Implements clause to your Dispose method, which the IDE would have done for you.
Your code could also cause run time errors that would be hard to diagnose. Take a look at the code that the IDE generates. Notice that there are two Dispose methods? It does that for a reason. You say:
As I am not using any unmanaged resources I have removed the if statement and the boolean
but that is the exact opposite of what you should be doing. The If statement and the Boolean filed exist SPECIFICALLY for managed resources. If you go back and read my post again I said:
If you have no managed resources then you can remove the first TODO, and therefore the If block too.
This is all done for a reason and it's explained in the documentation but here goes anyway. If an instance of your class is created and assigned to a variable and then that variable loses scope before the object is disposed, it's going to be left up to the GC to dispose your object when it finalises it. At that point your Dispose method will be called and it will try to dispose the WebClient. Who's to say that the GC hasn't already cleaned up that WebClient object though? If it has then you'll get an exception thrown for trying to access invalid memory. That's why you MUST NEVER release managed resources unless the object is being explicitly disposed, which is why you need two Dispose methods.
Just let the IDE implement the IDisposable interface for you and then follow the instructions it provides in the generated code. If you do that you know that it's done properly.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|