1

Consider the following pseudo code:

public class SomeComponent
{
    private List<DisposableFoo> _foos = new List<DisposableFoo>();

    public void Start()
    {
        for (int i = 0; i < 5; i++)
        {
            var foo = new DisposableFoo();
            var bar = new DisposableBar();                 <-- EXPLICIT DISPOSE NEEDED?
            foo.SomeFunc = x => bar.DoSomethingWithX(x);
            _foos.Add(foo);
        }
    }

    public void Stop()
    {
        _foos.ForEach(f => f.Dispose());
    }
}

Does the infrastructure take care of Disposing any captured IDisposable variables as part of it's tear down?

Clarification: I am not asking about best practices around managing disposable objects. My question is more about what does the infrastructure do in this instance. My understanding is that for capturing variables, behind the scenes the infrastructure creates a type that contains a field of type DisposableBar and it receives a reference to the object in the 'bar' variable. Once the infrastructure has captured that variable it seems like a 'gray area' to me about whose responsibility it is at that point to determine when the variable is no longer needed and can be disposed.

Casey Chester
  • 268
  • 3
  • 11
  • 1
    Are you asking if `bar` will be disposed automatically? Why would it? just because you are using it inside a lambda? – Zohar Peled Mar 09 '18 at 13:35
  • My understanding that in this instance the infrastructure creates a type automagically behind the scenes with a local field of type DisposableBar that receives a reference to the object stored in bar (i.e. the captured variable). My question is does the infrastructure detect that it is capturing a disposable instance and take care of proper disposal? – Casey Chester Mar 09 '18 at 14:46
  • 1
    @CaseyChester It is your responsibility to determine when it is no longer needed and disposed of. There is nothing special about the framework that handles this for you and nothing that scans anything different because the object is IDisposable. The only thing you get is extra syntax like the ```using``` statement to handle disposable objects for you. Disposing is only best practice; there is no gray area or mythical behind the scenes work. – Michael Puckett II Mar 09 '18 at 17:38
  • @CaseyChester And if you're asking what happens to a variable that you pull from a disposable object, after the disposable object is disposed, then as long as you have a reference to the object nothing happens. Your disposable object would have to write unique code to disrupt this behavior but with that in mind; it could happen. – Michael Puckett II Mar 09 '18 at 17:42
  • @CaseyChester I've updated my answer based on what I believe you're asking but I left the previous part of the answer also. – Michael Puckett II Mar 09 '18 at 18:09
  • 1
    @MichaelPuckettII You said 'the only thing you get is extra syntax like the using statement to handle disposable objects for you.' This is as close to an answer to my particular question as anyone has come so far. Since the implementation is generating a type and getting a reference to a disposable object 'behind the scenes' I started to wonder if it generates anything special for disposable types - like it does for using statement. I feel like I asked what time it was and everyone want to tell me how to build a clock or debate the merits of the theory of time itself. – Casey Chester Mar 10 '18 at 13:06

3 Answers3

2

The short answer is yes most definitely. You need to call dispose on any object that is disposable. This is used to clean up unmanaged resources and dependencies.

Also NOTE: The garbage collector does not call Dispose on or look for IDisposable types.

If it is disposable within the method then it is ideal to use a using statement like so.

public void Start()
{
    for (int i = 0; i < 5; i++)
    {
        using (var foo = new DisposableFoo())
        using (var bar = new DisposableBar())
        {
             foo.SomeFunc = x => bar.DoSomethingWithX(x);
             _foos.Add(foo);
        }
    }
}

If the variable is class level then your class should also implement IDisposable and dispose of the disposable objects it uses within it as well.

Here is a good link where I give more detail about disposing objects.

Another thing to keep in mind is that sometimes (in languages like C#) we can have circular dependencies (which is bad practice.) However; it happens a lot. If your object is garbage collected and there is a circular dependency it hangs around until the other object is also garbage collected and it causes the process to be ugly. It's all behind the scenes and usually isn't a big deal for most apps but being aware of this is important. Although you should not have circular dependencies you can implement IDisposable to clean up dependencies before going to the garbage collector, making this process cleaner. (Just remember having them is bad to start with... That said, Entity Framework is built on circular dependencies so go figure.)

Another NOTE: It is not uncommon to see the Dispose method added also to the destructor of an object; especially if the object is lower level, singleton, or static, to insure the disposable types are taken care of during garbage collection. This would look something like:

public class SomeClass : IDisposable
{
     //pretend we implement a singleton pattern here
     //pretend we implement IDisposable here
    ~SomeClass()
    {
        Dispose(); 
    }
}

UPDATE:

To update the answer based on your clarification I believe you're asking what happens to the variable you retrieve from a disposable object, after that disposable object is disposed. This is tricky behavior and should be thought out well when developing a disposable type. Here's some code that shows the results of similar situation that might help you understand. Also. whose responsible for this should be decided when developing the type but in most cases any information you give to the client should be left good for the client even after you're disposed. In other words, it would be best practice to NOT remove or dispose or manipulate any information you allow the user of your type to retrieve when you are disposing.

using System;
using System.Collections.Generic;
namespace Disposable_Variables_Reference
{
    class Program
    {
        static void Main(string[] args)
        {
            List<string> DCNames = null;
            string DCName = string.Empty;
            int DCValue;
            using (var disposableClass = new DisposableClass())
            {
                DCNames = disposableClass.Names;
                DCName = disposableClass.Name;
                DCValue = disposableClass.Value;
                foreach (var name in DCNames) Console.WriteLine(name);
                Console.WriteLine(DCName);
                Console.WriteLine(DCValue);
            }
            foreach (var name in DCNames) Console.WriteLine(name);
            Console.WriteLine(DCName);
            Console.WriteLine(DCValue);
            Console.Read();
        }

        public class DisposableClass : IDisposable
        {
            public List<string> Names { get; set; } = new List<string>() { "Michael", "Mark", "Luke", "John" };
            public string Name { get; set; } = "Gabriel";
            public int Value { get; set; } = 20;
            public void Dispose()
            {
                Names.Clear();
                Name = string.Empty;
                Value = 0;
            }
        }
    }
} 

Output:

Michael
Mark
Luke
John
Gabriel
20
Gabriel
20

Names is a List (reference type) and IS NOT re-written to the output.

Name is string (immutable reference type) and IS re-written to the output.

Value is int (value type) and IS re-written to the output.

However; if you reassign Names in the Dispose() method, instead of clearing it, then it WILL ALSO be re-written. Example including just the dispose method change.

public void Dispose()
{
    Names = null; //notice here we re-assign Names to null.
    Name = string.Empty;
    Value = 0;
}

New Output:

Michael
Mark
Luke
John
Gabriel
20
Michael
Mark
Luke
John
Gabriel
20

Knowing this the proper way to expose Names would be to leave it alone in the Dispose() method or expose name like so; returning a new list, so that any referendes to it are not removed when disposing.

private List<string> names = new List<string>() { "Michael", "Mark", "Luke", "John" };
public List<string> Names
{
    get { return names.ToList() ; }
    set { names = value; }
}

Of course this entire answer is for logic and clarification. There is no reason to use IDisposable in the DisposableClass example I've given.

Michael Puckett II
  • 6,586
  • 5
  • 26
  • 46
0

If you have used unmanaged code in DisposableBar than it needed to be disposed, else Garbage collator will take care managed resources.

programtreasures
  • 4,250
  • 1
  • 10
  • 29
  • 1
    Garbage collector does not take care of disposable or call dispose. It will clean up managed memory but the purpose for dispose it to clean up dependencies and unmanaged resources which will not happen. – Michael Puckett II Mar 09 '18 at 13:37
  • @MichaelPuckettII yes u r correct, I mention that if you have used unmannaged code than it needs to be disposed using dispose method, and the managed resources are disposed my CLR garbage collator – programtreasures Mar 09 '18 at 13:39
  • However; if you're not using unmanaged resources and you don't have tied dependencies then you shouldn't be implementing IDisposable. – Michael Puckett II Mar 09 '18 at 13:42
  • @MichaelPuckettII correct with you, what OP has asked that he is unsure of disposing `DisposableBar`, – programtreasures Mar 09 '18 at 13:43
  • And the correct answer would be yes. Always dispose of disposable objects. You might get away with it but it's bad practice and it could come back to bite you depending on the object. This should not pass a code review is all I'm saying. – Michael Puckett II Mar 09 '18 at 13:48
  • @MichaelPuckettII yes I agree with you the disposable object need to be dispose – programtreasures Mar 09 '18 at 13:59
  • @MichaelPuckettII we are on the same page just `interpretation` is different – programtreasures Mar 09 '18 at 14:03
  • see clarification added to original question – Casey Chester Mar 09 '18 at 16:11
  • @CaseyChester if you are not using using block than it will be clr garbage collector responsibility to remove from the memory, here bar will be no longer used after for block , so the gc will be mark unused and will be removed by gc. – programtreasures Mar 09 '18 at 16:30
-1

Yes and no. The proper thing to do will be to dispose manually. If this code is similar to the real app you should gather the bars in a list and dispose them after you dispose the foos. Depending on how your real code is structured you might need another strategy. If the bar is unmanaged resource you should always dispose it. In most cases the unmanaged resource is wrapped in a managed resource for example StreamReader wraps an unmanaged file handle. In these cases the object will be disposed when the managed object is garbage collected assuming that the dispose pattern is implemented correctly. The problem is that the GC is not deterministic and will run when there is memory pressure. There might be a situation where GC does not run but your app is starved for file handlers but since GC only cares about memory it does not run and the unmanaged resource is not disposed.

Stilgar
  • 22,354
  • 14
  • 64
  • 101
  • "In most cases the unmanaged resource is wrapped in a managed resource for example StreamReader wraps an unmanaged file handle. In these cases the object will be disposed when the managed object is garbage collected assuming that the dispose pattern is implemented correctly." - I tend to disagree with this statement. Garbage collector has nothing to do with IDisposable or disposing of objects. There are several steps the GB takes but it will not assist with unmanaged resources. On lower levels classes may implement IDisposable in the destructor, which will be called in the collector. – Michael Puckett II Mar 09 '18 at 14:16
  • A properly implemented disposable pattern on a managed resource which holds an unmanaged resource should always call Dispose (or equivalent code) in the destructor. Otherwise the implementation should be considered buggy. Here is an example from the FileStream class - https://referencesource.microsoft.com/#mscorlib/system/io/filestream.cs,0268f0f5e2f14824 – Stilgar Mar 09 '18 at 14:48
  • Ok, I'll give you that when you say 'assuming that the dispose pattern is implemented correctly.' I also made note of this issue in my answer and practice this as well. However, note the debug statement ```BCLDebug.Correctness(_handle.IsClosed, "You didn't close a FileStream & it got finalized. Name: \""+_fileName+"\"");``` which means it wasn't disposed properly to start with. Assuming something will happen is not good practice (and I'm guilty of this also) and I still feel the answer is misleading, in which case, I can also agree that it is technically correct. Apologies. – Michael Puckett II Mar 09 '18 at 15:48
  • The question is not what is the preferred way and what is more I have pointed out at the very start of my answer that the object should be disposed. The question is if the object will be disposed and if it is a managed wrapper (as most disposables are in practice) it will be disposed. – Stilgar Mar 09 '18 at 21:25