[C#] using (...), IDisposable - What is it? When should you use it?

Results 1 to 9 of 9
  1. #1
    [C#] using (...), IDisposable - What is it? When should you use it? Future is offline
    SupervisorRank
    Dec 2011 Join Date
    1,827Posts

    [C#] using (...), IDisposable - What is it? When should you use it?


    RaGEZONE Recommends

    RaGEZONE Recommends

    As I was showing a few friends a code snippet of a funny using chain, I found out how many C# programmers never understood the using() keyword in C#. So I thought maybe a little tutorial would do nicely?

    The problem (Why IDisposable?)

    To understand using() we need to understand the purpose of the IDisposable interface in C# first.

    What people tried in managed languages like Java or C# was taking the memory management away from the programmer. Working with pointers / doing allocations directly and scr*wing up with the needed cleanup / handling at all proved to be a big issue. App crashes everywhere because of that.
    They came up with the Garbage Collector, who from now one takes care of cleanups of allocated memory (= when you use new() you usually allocate).

    Having the GC (Garbage Collector) they felt that Destructors were not so important anymore as they were mostly used for memory cleanups when an object reached the end of it's lifetime. Even though they still "kept" them, they work in a very weird way and you basically rely on the GC to call them whenever it feels like it, without having any control over it. So better stay away from these in C#.

    This caused new issues for the programmers. We cannot detect if an object reaches the end of it's lifetime anymore. And we cannot react directly to that.

    There are some cases left where Destructors did something other than just cleaning memory up. Things like:

    • Closing a connection to a webserver
    • Closing a connection to an SQL server
    • Closing any other type of connection
    • Releasing externally used resources (GPU memory, Windows shared memory)
    • Closing a file handle

    on object disposal / destruction were not possible anymore.

    The IDisposable interface

    So C# came up with an Interface called "IDisposable" that can be implemented / inherit from any class that needs to to additional cleanups / handling of an objects disposal. The interface defines the abstract ".Dispose()" method that is supposed to be something like a destructor.

    IDisposable has nothing to do with memory management (inside the C# application) or Garbage Collection! It is NOT done by the CLR (Common Language Runtime) automatically! No, you cannot skip it!

    I highlighted this because I had someone ask me exactly this: "Huh? Why do I even need this? C# has Garbage Collection". That's the downside of it. It is the programmers / YOUR duty to call IDisposable.Dispose() once the Disposable object is no long in use!

    Examples

    Here are 3 examples of .NET classes that implement the IDisposable interface together with the reason why they do it. This might help you understand the purpose:

    The FileStream class
    The class System.IO.FileStream implements the IDisposable interface. It needs .Dispose() to be called in order to close the current stream and releases any resources (such as sockets and file handles) associated with the current stream.
    Know the explorer message: "Cannot access the file because it is used by another process" ? That's why you need to call .Dispose here :P

    The SqlConnection class
    The class System.Data.SqlClient.SqlConnection is a Component and as such has a .Dispose method. It will most likely close the connection to the SQL Server on dispose.

    The Font class
    The class System.Drawing.Font is disposable as well because it needs to release GDI (graphics device interface) resources associated with the Font.

    The using keyword

    What are we? Programmers. What do we do? Forget things.

    Having the issue that you need to call .Dispose() .Close() or whatever method that is intended to clean an object up, C# came up with the using keyword.
    This is both, nice to read and very useful when dealing with disposable objects.

    Here is a simple example:

    Code:
    using (FileStream fs = new FileStream("C:\\Users\\Me\\Desktop\\test.txt", FileMode.Create))
    {
        byte[] data = new UTF8Encoding(true).GetBytes("Hello");
        fs.Write(data, 0, data.Length);
    }
    See no .Dispose() call? That's right! using() will wait until the execution of the code within its body has finished (in any way) and then calls .Dispose() on the used object!
    Awesome, isn't it?

    It get's even better:

    Code:
    using (FileStream fs = new FileStream("C:\\Users\\Me\\Desktop\\test.txt", FileMode.Create))
    {
        byte[] data = new UTF8Encoding(true).GetBytes("Hello");
        if (fs.Write(data, 0, data.Length) != data.Length)
            return false;
    
        DoSometingElse();
    }
    Code:
    using (FileStream fs = new FileStream("C:\\Users\\Me\\Desktop\\test.txt", FileMode.Create))
    {
        byte[] data = new UTF8Encoding(true).GetBytes("Hello");
        if (fs.Write(data, 0, data.Length) != data.Length)
            throw new FileNotReadException("The file was not read correctly");
    
        DoSometingElse();
    }
    In both of these cases the closing bracket ("}") is not reached when the data was read improperly. However the .Dispose() method of the used disposable object will still be called!
    This lets you return / throw / do whatever you want inside the using scope and you can be sure that .Dispose() will still be called!

    So when you can use using(), DO IT!

    In some cases it will get a little funny...
    Spoiler:
    Code:
    using (SqlConnection conn = new SqlConnection(connStrBuilder.ConnectionString))
    {
    	using (SqlCommand cmd = new SqlCommand("SELECT ItemNum, ItemName, SourceIndex FROM ti_Item", conn))
    	{
    		using (SqlDataReader reader = cmd.ExecuteReader())
    		{
    			while (reader.Read())
    			{
    				Item item = FetchItem(reader);
    				using (FileStream fs = new FileStream(UserSettings.File.ClientDatabaseFileName, FileMode.Create))
    				{
    					using (BinaryWriter bw = new BinaryWriter(fs))
    					{
    						bw.Write(item.x........);
    					}
    				}
    			}
    		}
    	}
    }

    But this is likely never the case

    I hope this helps Beginners / Intermediates / w/e understand the using() and IDisposable a little better
    Last edited by Future; 02-09-16 at 12:32 PM. Reason: Destructors exist in C#, so I added that one shouldn't use them :P


  2. #2
    Developer Eronisch is offline
    True MemberRank
    Jul 2009 Join Date
    The NetherlandsLocation
    1,329Posts

    Re: [C#] using (...), IDisposable - What is it? When should you use it?

    Great explanation! A great addition to the post would be the disposable pattern.

  3. #3
    Deep thoughts [C#] using (...), IDisposable - What is it? When should you use it? Joopie is offline
    SubscriberRank
    Jun 2010 Join Date
    The NetherlandsLocation
    2,584Posts

    Re: [C#] using (...), IDisposable - What is it? When should you use it?

    Maybe worth noting here that the using keyword will be translated by the compiler as follow (using the first example of using from here):

    Code:
    FileStream fs = new FileStream("C:\\Users\\Me\\Desktop\\test.txt", FileMode.Create);
    try
    {
      byte[] data = new UTF8Encoding(true).GetBytes("Hello");
      fs.Write(data, 0, data.Length);
    }
    finally
    {
      if (fs != null)
        ((IDisposable)fs).dispose();
    }

    https://msdn.microsoft.com/en-us/library/yh598w02.aspx

  4. #4
    Hardcore Member Arachis is offline
    MemberRank
    Aug 2014 Join Date
    United StatesLocation
    121Posts

    Re: [C#] using (...), IDisposable - What is it? When should you use it?

    If you do happen to have a couple of these stacked, you can clear up some lines by removing their curly braces:
    Code:
    using (SqlConnection conn = new SqlConnection(connStrBuilder.ConnectionString))
    using (SqlCommand cmd = new SqlCommand("SELECT ItemNum, ItemName, SourceIndex FROM ti_Item", conn))
    using (SqlDataReader reader = cmd.ExecuteReader())
    {
    	while (reader.Read())
    	{
    		Item item = FetchItem(reader);
    		using (FileStream fs = new FileStream(UserSettings.File.ClientDatabaseFileName, FileMode.Create))
    		using (BinaryWriter bw = new BinaryWriter(fs))
    		{
    			bw.Write(item.x........);
    		}
    	}
    }

  5. #5
    [C#] using (...), IDisposable - What is it? When should you use it? Future is offline
    SupervisorRank
    Dec 2011 Join Date
    1,827Posts

    Re: [C#] using (...), IDisposable - What is it? When should you use it?

    Quote Originally Posted by Arachis View Post
    If you do happen to have a couple of these stacked, you can clear up some lines by removing their curly braces:
    Code:
    using (SqlConnection conn = new SqlConnection(connStrBuilder.ConnectionString))
    using (SqlCommand cmd = new SqlCommand("SELECT ItemNum, ItemName, SourceIndex FROM ti_Item", conn))
    using (SqlDataReader reader = cmd.ExecuteReader())
    {
    	while (reader.Read())
    	{
    		Item item = FetchItem(reader);
    		using (FileStream fs = new FileStream(UserSettings.File.ClientDatabaseFileName, FileMode.Create))
    		using (BinaryWriter bw = new BinaryWriter(fs))
    		{
    			bw.Write(item.x........);
    		}
    	}
    }
    I also ended up separating the SQL query side from the file writing side so it was far more readable.

    Great additions @Joopie & @Arachis !

    Quote Originally Posted by Eronisch View Post
    Great explanation! A great addition to the post would be the disposable pattern.
    I think Joopie just did this pretty simple / well. I might extend the post at a later point too, thx for the suggestion :)




    Quote Originally Posted by A Wise Man
    P-Servers are NOT dead. Bugs need squishing. Quests need fixing. Unfortunately, majority of people don't know the difference between a computer and a toaster so...

  6. #6
    Ultimate Member jaden83 is offline
    MemberRank
    Oct 2014 Join Date
    DESKTOP-2FLLV85Location
    176Posts

    Re: [C#] using (...), IDisposable - What is it? When should you use it?

    https://msdn.microsoft.com/en-us/library/66x5fx1b.aspx

    They're still deconstructors in C#.
    Jaden's like the Afrocentric Asian. Half man, half amazing.

  7. #7
    Deep thoughts [C#] using (...), IDisposable - What is it? When should you use it? Joopie is offline
    SubscriberRank
    Jun 2010 Join Date
    The NetherlandsLocation
    2,584Posts

    Re: [C#] using (...), IDisposable - What is it? When should you use it?

    Quote Originally Posted by jaden83 View Post
    https://msdn.microsoft.com/en-us/library/66x5fx1b.aspx

    They're still deconstructors in C#.
    Quick read, but the destructor is being called by the garbage collector. So you never know when, for example, the file is being unlocked. Using the disposal interface, you do have that sort of control.

  8. #8
    [C#] using (...), IDisposable - What is it? When should you use it? Future is offline
    SupervisorRank
    Dec 2011 Join Date
    1,827Posts

    Re: [C#] using (...), IDisposable - What is it? When should you use it?

    You should almost never use destructors in C#, really. I don't know why they even exist in the language. It is better to use the disposable pattern to ensure that the resource is cleaned up.

    You can read a lot of posts about why that is so. Basically destructors in C# work very weird because they depend upon the Garbage Collector which has the duty to call them. The GC will never run on one of your threads and that causes quite some problems:

    • An unhandled exception thrown from a destructor is bad news. It's on its own thread; who is going to catch it?
    • A destructor may be called on an object after the constructor starts but before the constructor finishes. A properly written destructor will not rely on invariants established in the constructor.
    • A destructor can "resurrect" an object, making a dead object alive again. That's really weird. Don't do it.
    • A destructor might never run; you can't rely on the object ever being scheduled for finalization. It probably will be, but that's not a guarantee.

    Taken from Stackoverflow

    Nonetheless I updated my question cus "C# has no destructors" is technically wrong.




    Quote Originally Posted by A Wise Man
    P-Servers are NOT dead. Bugs need squishing. Quests need fixing. Unfortunately, majority of people don't know the difference between a computer and a toaster so...

  9. #9
    what a twat is this hat? saamus is offline
    Alpha MaleRank
    Sep 2011 Join Date
    /etc/rc.localLocation
    2,212Posts

    Re: [C#] using (...), IDisposable - What is it? When should you use it?

    Quote Originally Posted by Future View Post
    You should almost never use destructors in C#, really. I don't know why they even exist in the language. It is better to use the disposable pattern to ensure that the resource is cleaned up.

    You can read a lot of posts about why that is so. Basically destructors in C# work very weird because they depend upon the Garbage Collector which has the duty to call them. The GC will never run on one of your threads and that causes quite some problems:

    • An unhandled exception thrown from a destructor is bad news. It's on its own thread; who is going to catch it?
    • A destructor may be called on an object after the constructor starts but before the constructor finishes. A properly written destructor will not rely on invariants established in the constructor.
    • A destructor can "resurrect" an object, making a dead object alive again. That's really weird. Don't do it.
    • A destructor might never run; you can't rely on the object ever being scheduled for finalization. It probably will be, but that's not a guarantee.

    Taken from Stackoverflow

    Nonetheless I updated my question cus "C# has no destructors" is technically wrong.
    Exactly! Give an Oscar for this guy.




Advertisement