0

When creating an element that implements IDisposable, Dispose() is called at the end of the using block also if an exception is thrown, if I'm correct.

However, when creating a new element of ClassB within the constructor of a disposable element, will the object of ClassB also be disposed if IDisposable is implemented?

using (ClassA a = new ClassA(new ClassB()))
{
}

This may apply to classes that are related to Stream. However, does this apply in general?

bytecode77
  • 14,163
  • 30
  • 110
  • 141
  • 4
    No. Its is not created within the constructor, but **before** the constructor. – dymanoid Jun 15 '16 at 13:17
  • 1
    It would be messed up if it did. You could create a ClassB that implement IDisposable and test with about as many key strokes as this question. – paparazzo Jun 15 '16 at 13:24

2 Answers2

5

ClassB would only be disposed if the dispose method of ClassA calls dispose on it.

class ClassA : IDisposable
{
    private ClassB b;
    public ClassA (ClassB b) { this.b = b; }
    public void Dispose() { this.b.Dispose(); }
}

If it doesn't you'll need to dispose of it separately:

using (ClassB b = new ClassB())
using (ClassA a = new ClassA(b))
{
}
Trevor Pilley
  • 16,156
  • 5
  • 44
  • 60
  • 1
    Even in the first case an exception in the `ClassA` constructor would result in leaking the `ClassB` instance. – Servy Jun 15 '16 at 13:20
  • So better not trust any class... Is there any way of finding out if a class also disposes of its constructor parameters other than decompiling? Streams seem to do that. But is there a general pattern? – bytecode77 Jun 15 '16 at 13:24
  • @bytecode77 If it's documented as disposing of the resource, assume it will dispose of it. If it doesn't explicitly state that it does, assume it doesn't. – Servy Jun 15 '16 at 13:24
  • 2
    @bytecode77, it is actually not a good practice to dispose injected objects. The example 1 in this answer is a bad decision. What if a `ClassB` object is shared among many `ClassA` instances? – dymanoid Jun 15 '16 at 13:25
  • It *should* be safe to call Dispose multiple times so even if `ClassA` did dispose of `ClassB`, if you used the second example it shouldn't cause a problem – Trevor Pilley Jun 15 '16 at 13:26
  • But then the `ClassB` object is in a disposed state, and when another `ClassA`object tries to use it, we get for example an `ObjectDisposedException` or the object won't work as expected, depending on implementation. – dymanoid Jun 15 '16 at 13:27
  • @dymanoid - (first comment) not necessarily, there are occasions where you might need to do that (e.g. if you have a factory method which returns an `IThing` but the `Thing` implementation needs some other resource which is `IDisposable`) (second comment) - that is true, this isn't supposed to be code review though, I'm simply answering the question of when `ClassB` would get disposed... – Trevor Pilley Jun 15 '16 at 13:28
  • [Here](http://stackoverflow.com/a/1065196/1997232) is an example of first scenario (somewhat). You simply should know what will happens with object once you pass it to other object. – Sinatr Jun 15 '16 at 13:30
  • @dymanoid: If the last user of an object that wraps a resource will know nothing about the resource in question, the wrapper will likely be the only thing that *can* dispose the resource. If a wrapper may be used with either shared or unshared resources, its constructor should allow the supplier of the resource to indicate whether the new object should take ownership. – supercat Jun 17 '16 at 19:06
1

Short answer, no. If ClassB implements IDisposable, you should wrap it in a using block too:

using (var b = new ClassB())
using (var a = new ClassA(b))
{
    // do stuff
}

Keep in mind that everything you pass to a constructor, or any other method which accepts parameters is evaluated before the constructor or method is invoked.

Some classes, like StreamWriter does with a Stream, will dispose whatever is passed through the constructor, but it's common to leave the disposing to whoever actually instantiated the object.

vgru
  • 49,838
  • 16
  • 120
  • 201