I want a method to return an unmanaged resource and later in the program dispose of that resource. Does the following implementation do what I intend ?
class DocxManager
{
// DocX is the unmanaged resource
public Docx createDocX(string pathToFile)
{
return new DocX(pathToFile);
}
public void makeChangesAndSaveDocX(DocX wordDoc)
{
wordDoc.Save();
// IS THIS WAY THE UNMANAGED RESOURCE FREED CORRECTLY AND NO MEMORY LEAK ?
((IDisposable)wordDoc).Dispose();
}
}
First off all, you seem to be misunderstanding the concept of managed and unmanaged resources.
wordDocis not an unmanaged resource, its a managed resource which happens to either directly hold an unmanaged resource or acts as a wrapper around some otherIDisposableobject (you don't care wich of the two is true). Its important you are clear on this because otherwise you will not implement correctly theIDisposablepattern when you need to. Read this for a very instructive answer on the subject and a few chuckles courtesy of Eric Lippert.No, it does not and to make things worse, the contract of
DocXManageris simply horrible (more on that later).What hapens if
wordDoc.Save()throws and exception because the file is being used by another process, or maybe you've run out of space in the hard drive, or you've lost connection, etc.?If the thrown exception is not recoverable (it's not handled anywhere in your code or it is but you will terminate it ASAP) then it's not really an issue and the runtime will clean up everything behind you when the process is terminated. On the other hand, if the exception is handled (warn the user the file is in use, the directory is not available, etc.) and the process keeps running then you've just maybe leaked a resource.
How to avoid this? Use a
try-finallyblock:Now you are sure that
Dispose()will be called in any recoverable scenario.So, is this good enough? Well....not exactly. The problem here is that
makeChangesAndSaveDocX's (that should beMakeChangesAndSaveDocXby the way) contract is unclear. Who is responsible of disposingwordDoc?MakeChangesAndSaveDocXor the caller? Why one or the other? How does the consumer know that he doesn't need to worry aboutwordDoconce he's calledMakeChangesAndSaveDocX? Or how is he supposed to know he can't usewordDocafter calling the public methodMakeChangesAndSaveDocX? Why doesDocXManagerassume that the consumer will not need to usewordDocafter callingMakeChangesAndSaveDocX? Yuck...this is a mess.I'd recommend you reconsider your approach and do one of the following:
MakeChangesAndSaveDocX(DocX wordDoc)makes sense (somebody else can ownwordDoc), then do not disposewordDocinMakeChangesAndSaveDocX. Let the caller carry that burden, he should be responsible because the object belongs to him not toMakeChangesAndSaveDocX.If on the other hand, it makes no sense that somebody else who is not
DocXManagerownswordDocthenwordDocshould be part of the state ofDocXManagerand you should reconsider the implementation ofDocXManagerto something allong the following lines:Now you've got a clear contract;
DocManagerXis responsible of disposing correctly ofDocXand the consumer is responsible of disposing correctly of any instance ofDocManagerXhe might use. Once responsibilities are clear, its easier to reason about code correctness and who should do what.You'd use the manager in the following way: