Using comRel As New ComReleaser() pFeatureCursor = pFeatureClass.Update(pQueryFilter, False) comRel.ManageLifetime(pFeatureCursor) pFeature = pFeatureCursor.NextFeature Do While Not pFeature Is Nothing ' Do something pFeatureCursor.UpdateFeature(pFeature) pFeature = pFeatureCursor.NextFeature Loop pFeatureCursor.Flush() End Using
Using comRel As New ComReleaser() pFeatureCursor = pFeatureClass.Update(pQueryFilter, False) comRel.ManageLifetime(pFeatureCursor) pFeature = pFeatureCursor.NextFeature Do While Not pFeature Is Nothing ' Do something Using comRel2 as New ComReleaser() pFeatureCursor2 = pFeatureClass2.Search(pQueryFilter2, False) comRel2.ManageLifetime(pFeatureCursor2) ' Do something inner looping stuff End Using pFeatureCursor.UpdateFeature(pFeature) pFeature = pFeatureCursor.NextFeature Loop pFeatureCursor.Flush() End Using
Using comRel As New ComReleaser() pFeatureCursor = pFeatureClass.Update(pQueryFilter, False) comRel.ManageLifetime(pFeatureCursor) pFeature = pFeatureCursor.NextFeature Do While Not pFeature Is Nothing ' Do something pFeatureCursor2 = pFeatureClass2.Search(pQueryFilter2, False) comRel.ManageLifetime(pFeatureCursor2) ' Do something inner looping stuff End Using pFeatureCursor.UpdateFeature(pFeature) pFeature = pFeatureCursor.NextFeature Loop pFeatureCursor.Flush() End Using
Solved! Go to Solution.
Neil and Jason,
Thank you for telling me why I should not be using comReleaser! ESRI use it in many of their code examples so this is why I have adopted it as I understood it guaranteed the release of the cursor but as Jason shows that is not always the case and using Marshal.ReleaseComObject is a more robust solution.
BUT, I can't help noticing this does not answer my question...;)
If you are using comReleaser what is the best practise when you have nested loops? Neil points out it is an ESRI class, may be one the the ESRI product developers can answer this question?
Duncan
Using comRel As New ComReleaser() pFeatureCursor = pFeatureClass.Update(pQueryFilter, False) comRel.ManageLifetime(pFeatureCursor) pFeature = pFeatureCursor.NextFeature Do While Not pFeature Is Nothing ' Do something pFeatureCursor2 = pFeatureClass2.Search(pQueryFilter2, False) comRel.ManageLifetime(pFeatureCursor2) ' Do something inner looping stuff End Using pFeatureCursor.UpdateFeature(pFeature) pFeature = pFeatureCursor.NextFeature Loop pFeatureCursor.Flush() End Using
Dim featureCursor As IFeatureCursor = featureClass.Search(Nothing, False) Dim feature As IFeature = featureCursor.NextFeature Do While feature IsNot Nothing ' do something with the feature Marshal.ReleaseComObject(feature) feature = featureCursor.NextFeature Loop Marshal.ReleaseComObject(featureCursor)
Neil and Jason,
Thank you for telling me why I should not be using comReleaser! ESRI use it in many of their code examples so this is why I have adopted it as I understood it guaranteed the release of the cursor but as Jason shows that is not always the case and using Marshal.ReleaseComObject is a more robust solution.
BUT, I can't help noticing this does not answer my question...;)
If you are using comReleaser what is the best practise when you have nested loops? Neil points out it is an ESRI class, may be one the the ESRI product developers can answer this question?
Duncan
Using comRel As New ComReleaser() pFeatureCursor = pFeatureClass.Update(pQueryFilter, False) comRel.ManageLifetime(pFeatureCursor) pFeature = pFeatureCursor.NextFeature Do While Not pFeature Is Nothing ' Do something pFeatureCursor2 = pFeatureClass2.Search(pQueryFilter2, False) comRel.ManageLifetime(pFeatureCursor2) ' Do something inner looping stuff End Using pFeatureCursor.UpdateFeature(pFeature) pFeature = pFeatureCursor.NextFeature Loop pFeatureCursor.Flush() End Using
The Using statement scopes the resource (the variable you declare) to the block of code between the Using and End Using statements. The purpose of the Using statement is to limit the scope of a resource within a larger block of code and to guarantee that it is disposed as soon as the End Using statement is executed. So, is it ok to nest Using statements? Yes. It's really no different than nesting loops or If/End If blocks. In your case, you're using a cursor within a loop. Each loop iteration opens a new cursor. That cursor needs to be released with each loop iteration. Each time a cursor is created, a table in the database is opened. It will not be closed until the cursor is released, so if you don't release the cursor within each loop iteration it will keep opening tables and not closing them. Eventually, you'll hit the max. number of open tables and an exception will be thrown. So, that cursor needs to be managed by its own ComReleaser object declared within the loop. If you use the ComRelease declared outside of the loop then the cursors created inside the loop will not be released until after the loop is exited.
IMO, the best practice is not to use ESRI's ComReleaser class at all. The best way to manage your COM objects is to do it yourself so that you know what's going on and have full control over it. When looping through a cursor, you should also be releasing the row/feature objects within the loop before assigning the reference to the next item in the cursor.Dim featureCursor As IFeatureCursor = featureClass.Search(Nothing, False) Dim feature As IFeature = featureCursor.NextFeature Do While feature IsNot Nothing ' do something with the feature Marshal.ReleaseComObject(feature) feature = featureCursor.NextFeature Loop Marshal.ReleaseComObject(featureCursor)
Is feature a managed or unmanaged object?
If it is a managed object, wouldn't the fact that the previous feature reference make it eligible for garbage collection in .NET? Otherwise, I agree, you should release it.
http://msdn.microsoft.com/en-us/library/ee787088.aspx#manipulating_unmanaged_resources
In fact, you can't directly use COM objects, you use an RCW, which is managed and eligible for garbage collection, to interact and marshal data back and forth between your .NET code and COM code. The RCW will eventually be collected by the .NET GC and will release the COM object. But, the problem is that it is done at the whim of the GC and not immediately.
In this case, the cursor needs to be released immediately because it has a table open, so we can't wait around on the GC to do its thing. Rather than waiting on the GC, you can tell the RCW to let go of the COM object by calling Marshal.ReleaseComObject on it. The RCW sticks around and waits to be collected by the GC, but it disconnects itself from the COM object it was helping you communicate with.