What is the main goal of
IDisposable
?Is it only a design pattern for finalization logic separation?
Its goal is simply to be a standard interface to call that logic. The recommended implementation separates manual disposing (Dispose(true)
) from Dispose called from the finalizer (Dispose(false)
) simply for efficiency -- it's redundant to dispose internal fields from within the finalizer because, since finalizers can't be called manually, we know at that point they must be already being collected.
Manual disposal is needed because garbage collection is not immediate (and you can't force collection of an individual object alone). This is more than just an efficiency concern, because it's possible that the unmanaged resource doesn't support multiple access, so another object accessing it later will fail if the first was not yet collected. Collection isn't even guaranteed, because as Ricibob showed, putting the code inside an explicit scope doesn't stop an external object from getting its own reference.
- And does, for example, Java, provide something similar?
using
is simply an auto-implemented "try ... finally" block that calls a pre-defined method.
Java includes this feature as an extension of the try
statement itself. This works the same as using
, except that it also allows you to add your own catch
and finally
blocks without needing to wrap it in an additional try
block.
Python has context managers which are a more flexible version of this. A context manager can define specific exception handling as well as the finally
, and may return a different object than what was passed in -- that is, this would be possible:
with CustomDisposer(MemoryStream()) as memoryStream:
where the CustomDisposer
object is responsible for the dispose implementation, yet it returns the MemoryStream
as the resource to be assigned to the memoryStream
variable.
Ruby has a yield
statement that allows a function to wrap a code block and optionally give a parameter to the block, so you can implement this by passing the given object to the block and then calling dispose in ensure (finally
equivalent):
def using(o)
yield o
ensure
o.dispose
end
using MemoryStream.new do |memoryStream|
#Operate with memory stream
end
Of course, since this is part of a function definition, there is no need for a dedicated using
function -- it could be directly implemented in the MemoryStream.Open
method for example.