14

I've got a bunch of IDisposable objects in a lookup table (plain old Dictionary<>, right now), but to simplify the code and avoid error's I'm looking for a collection class which "owns" the items it holds, and to avoid reinventing the wheel - does such a class already exist?

The specification should be that: - The collection must be disposable, and when it is disposed all contained items should be disposed too. - Whenever an item is removed, it is Dispose()-d first. - ideally, the collection would be generic with the type constraint enforcing the IDisposable-ness of the contained type.

I sorta doubt such a class exists, but I've been pleasantly surprised by the existence of ReadOnlyCollection and ObservableCollection before...

Essentially, I'd like the equivalent of the C++ STL containers but then for the CLR ;-).

Eamon Nerbonne
  • 47,023
  • 20
  • 101
  • 166
  • It's been a little while. Did you make an IDisposableCollection? I could use it too. – JohnV Oct 27 '10 at 01:06
  • No; I ended up wrapping the collection and exposing just the (very) few methods I actually needed - add/get/delete - and some additional functionality for the particular thing I worked on (lots of file-system watchers). – Eamon Nerbonne Oct 27 '10 at 09:59

5 Answers5

9

You're looking for CompositeDisposable.

    using System.Reactive.Disposables;

    ...

    CompositeDisposable xs = new CompositeDisposable(Disposable.Empty);
    xs.Add(Disposable.Empty);
    xs.Add(Disposable.Empty);
    xs.Dispose();
James Moore
  • 8,636
  • 5
  • 71
  • 90
  • 1
    Non generic. That's not quite ideal; but not a huge issue either. – Eamon Nerbonne Oct 16 '17 at 09:43
  • 1
    Rx extensions are not part of .net framework. While not a problem for many, it'll be not very good idea to reference entire library just for one trivial class. – arbiter Oct 16 '17 at 14:12
  • @arbiter has a point, although IMHO there's not much point in not using Rx. Once you've made the decision to pull in the gargantuan overhead of using .net in a project, no one should quibble about bringing in useful libraries. – James Moore Oct 16 '17 at 15:40
3

From what I know, there is only exits such collection for IComponents - Container implements IContainer. For generic IDisposable I think you have no other options but "reinvent the wheel".

arbiter
  • 9,447
  • 1
  • 32
  • 43
  • Thanks, I'll look into it (though it looks a little heavy weight - the API has a bunch of stuff I wouldn't be using - that might not matter)! – Eamon Nerbonne Jul 20 '09 at 14:53
  • Container and System.ComponentModel seem overly complex and insufficiently flexible for general use. In short, I'm accepting your answer that I have no other options but to "reinvent the wheel". – Eamon Nerbonne Jul 24 '09 at 11:52
3

How about something like this:

public class DisposableEnumerable<T> : IEnumerable<T>, IDisposable where T : IDisposable
{
    IEnumerable<T> Enumerable { get; }

    public DisposableEnumerable(IEnumerable<T> enumerable)
    {
        Enumerable = enumerable;
    }

    public IEnumerator<T> GetEnumerator()
    {
        return Enumerable.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return Enumerable.GetEnumerator();
    }

    public void Dispose()
    {
        foreach(var disposable in Enumerable)
        {
            disposable.Dispose();
        }
    }
}
  • I think a lazy enumerable as an argument here is at least tricky; it's important to know that the objects you pass in are really disposed. Of course, if the collection is not modified it doesn't matter. – Eamon Nerbonne Oct 16 '17 at 09:41
  • Also: even though it should not happen, you should consider what happens if an underlying `Dispose()` throws. – Eamon Nerbonne Oct 16 '17 at 09:41
1

Remember that your collection might not be the only one containing the disposable objects ... What if another object (external to the collection) is referencing one of those? If you dispose it when the collection is disposed, then what would happen to the object?

If these objects implement IDisposable for some unmanaged resources cleaning then make sure they implement finalization as well and dispose of unmanaged resources there.

bruno conde
  • 47,767
  • 15
  • 98
  • 117
  • I currently fully control both the objects and the collection - so this is a hypothetical situation. In any case; that's just the way things work with IDisposables, right? I mean, *somebody* has to own (i.e. eventually Dispose) them, and in this case the owner happens to own a variable number of IDisposables, so a collection would be simplest. – Eamon Nerbonne Jul 20 '09 at 14:49
0

I see what you're asking but how hard is it to make your own remove method that disposes the element before you remove it?

Sharath
  • 101
  • 1
  • 1
  • 3
  • Not hard at all - but it'd be cleaner to avoid it if possible. And, it's not just Remove, right - any method which may overwrite an element is implicitly replacing an existing element, which would need to be Dispose()'d too. If your collection implements a few standard interfaces, there can be quite a few variants of these remove/setter functions, leading to code bloat. – Eamon Nerbonne Jul 20 '09 at 14:51
  • https://blog.stephencleary.com/2009/08/third-rule-of-implementing-idisposable.html + https://www.codeproject.com/Articles/29534/IDisposable-What-Your-Mother-Never-Told-You-About + tools like SonarQube tend to complain a lot until you follow the full old pattern – quetzalcoatl Jun 05 '23 at 10:44