Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

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

[emoji848]
Legend
Joined
Dec 3, 2011
Messages
2,232
Reaction score
1,518
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 , 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 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 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 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 is a 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 is disposable as well because it needs to release resources associated with the Font.

The using keyword

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

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 .
This is both, nice to read and very useful when dealing with disposable objects.

Here is a simple example:

Code:
[COLOR="#0000FF"]using ([/COLOR]FileStream fs = new FileStream("C:\\Users\\Me\\Desktop\\test.txt", FileMode.Create)[COLOR="#0000FF"])
{[/COLOR]
    byte[] data = new UTF8Encoding(true).GetBytes("Hello");
    fs.Write(data, 0, data.Length);
[COLOR="#0000FF"]}[/COLOR]

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:
[COLOR="#0000FF"]using ([/COLOR]FileStream fs = new FileStream("C:\\Users\\Me\\Desktop\\test.txt", FileMode.Create)[COLOR="#0000FF"])
{[/COLOR]
    byte[] data = new UTF8Encoding(true).GetBytes("Hello");
    if (fs.Write(data, 0, data.Length) != data.Length)
[B][COLOR="#FF0000"]        return false;[/COLOR][/B]

    DoSometingElse();
[COLOR="#0000FF"]}[/COLOR]

Code:
[COLOR="#0000FF"]using ([/COLOR]FileStream fs = new FileStream("C:\\Users\\Me\\Desktop\\test.txt", FileMode.Create)[COLOR="#0000FF"])
{[/COLOR]
    byte[] data = new UTF8Encoding(true).GetBytes("Hello");
    if (fs.Write(data, 0, data.Length) != data.Length)
[B][COLOR="#FF0000"]        throw new FileNotReadException("The file was not read correctly");[/COLOR][/B]

    DoSometingElse();
[COLOR="#0000FF"]}[/COLOR]

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...
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 :p:

I hope this helps Beginners / Intermediates / w/e understand the using() and IDisposable a little better :thumbup1:
 
Last edited:
Developer
Member
Joined
Jul 28, 2009
Messages
983
Reaction score
133
Great explanation! A great addition to the post would be the disposable pattern.
 
Joined
Jun 23, 2010
Messages
2,318
Reaction score
2,195
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();
}


 
RaGEZONE VIP
[VIP] Member
Joined
Aug 13, 2014
Messages
121
Reaction score
239
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........);
		}
	}
}
 
[emoji848]
Legend
Joined
Dec 3, 2011
Messages
2,232
Reaction score
1,518
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 !

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 :)
 
Junior Spellweaver
Joined
Oct 26, 2014
Messages
176
Reaction score
117


They're still deconstructors in C#.
 
[emoji848]
Legend
Joined
Dec 3, 2011
Messages
2,232
Reaction score
1,518
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

Nonetheless I updated my question cus "C# has no destructors" is technically wrong.
 
Joined
Sep 2, 2011
Messages
2,171
Reaction score
916
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

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

Exactly! Give an Oscar for this guy.
 
Back
Top