Passing IDisposable as a parameter
Is it a good practice to pass IDisposable as a parameter to a method and dispose it inside that method. This is sort of inevitable when you have to use several threads. Well, the best practices says the owner(caller) should dispose it.
E.g.
public void MyMethod(MyClass reader){
using(reader){
//some code
}
}
What if the owner (creating thread) no longer exist? E.g.
interface IReader : IDisposable {
string Read();
}
public class MyReader : IReader {
public string Read()
{
return "hellow world";
}
public void Dispose()
{
//dispose code
}
}
Here you find the problem...
public void Start() {
MyReader[] readerSet = new MyReader[5];
for (int i = 0; i < readerSet.Length; i++) {
readerSet[i] = new MyReader();
}
foreach (IReader reader in readerSet) {
开发者_开发知识库 ThreadPool.QueueUserWorkItem(new WaitCallback(Run), reader);
}
//exit after creating threads
}
public void Run(Object objReader) {
IReader reader = (IReader)objReader;
using (reader) {
//use the reader
}
}
I think you would be better off taking a creation delegate to guarantee disposal of the object.
Example
public void Start() {
var makeReader = new Func<IReader>(() => new MyReader());
for (int i = 0; i < 5; i++) {
ThreadPool.QueueUserWorkItem(Run, makeReader);
}
}
public void Run(Object state) {
var makeReader = (Func<IReader>)state;
using (var reader = makeReader()) {
//use the reader
}
}
No, the owner should dispose it. The owner is usually an object that created IDisposable instance in the first place. You can read about IDisposable best practices here.
Do transitively dispose of any disposable fields defined in your type from your Dispose method. You should call Dispose() on any fields whose lifecycle your object controls. For example, consider a case where your object owns a private TextReader field. In your type's Dispose, you should call the TextReader object's Dispose, which will in turn dispose of its disposable fields (Stream and Encoding, for example), and so on. If implemented inside a Dispose(bool disposing) method, this should only occur if the disposing parameter is true—touching other managed objects is not allowed during finalization. Additionally, if your object doesn’t own a given disposable object, it should not attempt to dispose of it, as other code could still rely on it being active. Both of these could lead to subtle-to-detect bugs.
It may be a good idea to minimize passing IDisposable instances around so that you don't have to think about owners too much.
That entirely depends on your specific situation.
Generally, the “owner” should dispose the object, but it's your job to figure out who that is. It might not be the creator and it might not be the caller in your case either.
At any moment in time from the moment of its creation to its Dispose call, any instance of IDisposable should have precisely one owner who will be responsible for deleting it. Typically, the owner of an IDisposable will be the entity that created it, but there are cases where it may be helpful to have an object hand off ownership of an IDisposable to another object. Consider, for example, the following two hypothetical classes:
- SoundSource, which implements a GetAudio method that returns the next 'n' samples of a sound. SoundSource implements IDisposable because it can be used to stream audio from a file; if it's not properly disposed, the file won't get closed.
- AsyncSoundPlayer, which implements a PlaySound method that accepts a SoundSource and starts it playing, aborting any previous playing sound.
In many situations, the routine which loads a SoundSource won't really care when it gets done playing; it's apt to be more convenient to have the playback routine take ownership of the SoundSource. Note that in some cases the routine that requests playback might want to keep ownership of the SoundSource. The best approach is to allow a means by which the caller of a routine can specify whether it wishes to keep or hand off ownership of a passed-in IDisposable.
精彩评论