Click here to Skip to main content
6,822,123 members and growing! (17,587 online)
Email Password   helpLost your password?
Languages » C# » General     Intermediate License: The Code Project Open License (CPOL)

Using Keyword Can Cause Bugs

By Paulo Zemek

This article shows why not even the "using" keyword is a failsafe mechanism
C#, .NET, Dev
Revision:2 (See All)
Posted:27 Nov 2009
Views:4,027
Bookmarked:11 times
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
23 votes for this article.
Popularity: 5.91 Rating: 4.34 out of 5
1 vote, 4.3%
1

2
6 votes, 26.1%
3
3 votes, 13.0%
4
13 votes, 56.5%
5

Introduction

C# is a safe and managed language. By safe, we can understand it will help developers avoid common errors like causing memory leaks. This really works, but for some developers, this is not in the best way. For example, in C++, I wrote:

AutoTransaction transaction;
... some code here...
transaction.Commit();

And, if some exception was thrown, the AutoTransaction destructor will be called immediately.

To start, I can't do it the same way in C#, so I will use the first "natural" equivalent:

AutoTransaction transaction = new AutoTransaction();
... some code here...
transaction.Commit();

I could use var instead of the first AutoTransaction declaration, but that's not the problem. If an exception is thrown, the "destructor" will not be called immediately. It will be called, but not at this moment. So, I consider this a bug in my code, as it can cause many time-outs in the database. So, I would need to write something like this:

using(AutoTransaction transaction = new AutoTransaction())
{
  ... some code here...
  transaction.Commit();
}

This way, the compiler will generate the well known structure:

AutoTransaction transaction = new AutoTransaction();
try
{
  ... code here...
}
finally
{
  // in theory there is an if (transaction != null) here, 
  // but I think optimization will remove it.
  transaction.Dispose();
}

Using keyword is really a good shortcut. If you try this, you will notice that Dispose() will be called freeing the transaction immediately... most of the time.

And so, there is the real problem. I already did some interview tests with only invalid questions, like:

  • The right one is using (in general, this is the right answer, even not being the real one).
  • The right one is the new/try/finally Dispose. Also, considered the right one.
  • Declare the variable with null. In try, you alloc it, in finally, you test if it is different than null and, if it is, call Dispose. And, what you think? This is also considered right in some tests. But, none is correct.

Imagine a very unfair and competitive world.

AutoTransaction transaction = new AutoTransaction();

// another thread causes an abort HERE!

try

But, I spoke about an alternative. Declaring the variable with null and allocating it in try. So, the code:

AutoTransaction transaction = null;
try
{
  transaction = new AutoTransaction();
}
finally
{
  if (transaction != null)
    transaction.Dispose();
}

Now, you say:

  • Ok, if the Abort() appears just before the try, there is no problem (I agree);
  • If the Abort() appears just before the transaction = new AutoTransaction(); there is no problem (and I agree again);
  • If the Abort appears just after the transaction = new AutoTransaction(); there is no problem (and I agree again);

So, there is no problem (and I disagree).

Why?

Because, even being in the same line, the transaction = is one command and the new AutoTransaction is another command.

The Abort() can happen just in the middle. So, the AutoTransaction is created, its pointer is not set to the variable, the Abort() happens and the finally does nothing.

Well, at this point, we see that using keyword or the try/finally blocks are useless... except for the fact that finally runs. So, to solve our problem, our allocation must also be in the finally block.

So:

AutoTransaction transaction = null;
try
{
  try
  {
  }
  finally
  {
    transaction = new AutoTransaction();
  }
}
finally
{
  if (transaction != null)
    transaction.Dispose();
}

This will work... but, of course, the AutoTransaction has nothing of "Auto" in it, as it had in C++. Of course, in C++ you couldn't abort threads, as this could cause memory leaks. But, the difference, as C++ did always say you could not abort threads, is that there it was not used. But, in C#, or better, in the ASP.NET world, IIS uses it a lot... and no one guarantees you would be in the right place. To make it worse, imagine you are using the "using" keyword to make unsafe calls safe. You just caused a great and a hard to find bug, hard to happen (but that will happen) bug.

In the attached files, a sample that will create a file and dispose it. But, using the "using" keyword and the try block I presented here, the "file is being used by another process" exception is always caused by the "using" keyword.

I hope this makes web-developers think again when using the "using" keyword to make "sure" everything is ok and cleaned.

History

  • 27th November, 2009: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Paulo Zemek


Member

Location: Brazil Brazil

Other popular C# articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 25 of 45 (Total in Forum: 45) (Refresh)FirstPrevNext
GeneralMy Vote of 3: No Proof Pinmemberaspdotnetdev13:35 5 Dec '09  
GeneralRe: My Vote of 3: No Proof PinmemberPaulo Zemek2:03 7 Dec '09  
GeneralRe: My Vote of 3: No Proof PinmemberPaulo Zemek2:11 7 Dec '09  
GeneralRe: My Vote of 3: No Proof Pinmemberaspdotnetdev5:55 7 Dec '09  
GeneralRe: My Vote of 3: No Proof Pinmemberaspdotnetdev7:51 7 Dec '09  
GeneralRe: My Vote of 3: No Proof Pinmemberaspdotnetdev5:58 7 Dec '09  
GeneralRe: My Vote of 3: No Proof PinmemberPaulo Zemek7:41 7 Dec '09  
GeneralRe: My Vote of 3: No Proof Pinmemberaspdotnetdev7:49 7 Dec '09  
GeneralRe: My Vote of 3: No Proof [modified] PinmemberPaulo Zemek8:03 7 Dec '09  
GeneralRe: My Vote of 3: No Proof Pinmemberaspdotnetdev9:29 7 Dec '09  
GeneralRe: My Vote of 3: No Proof [modified] PinmemberPaulo Zemek10:41 7 Dec '09  
Generalnice article but... Pinmemberurix937:10 1 Dec '09  
GeneralRe: nice article but... [modified] PinmemberPaulo Zemek7:29 1 Dec '09  
GeneralMy vote of 1 PinmemberDr. Jones DK2:52 1 Dec '09  
GeneralRe: My vote of 1 PinmemberJohn Kasra18:54 25 Dec '09  
GeneralNice analysis PinmemberCurtainDog18:31 30 Nov '09  
GeneralRe: Nice analysis PinmemberPaulo Zemek1:38 1 Dec '09  
Generalexcellent job dude PinmemberBishoy Ghaly10:11 30 Nov '09  
GeneralRe: excellent job dude PinmemberPaulo Zemek10:28 30 Nov '09  
GeneralOk, I have investigated your source code and made a re-vote, but is the IO exception what you are talking about? [modified] PinmemberMiller48:00 29 Nov '09  
GeneralRe: Ok, I have investigated your source code and made a re-vote, but is the IO exception what you are talking about? PinmemberPaulo Zemek2:03 30 Nov '09  
GeneralFrom J.Duffy's blog Pinmemberreflex@codeproject9:24 28 Nov '09  
GeneralRe: From J.Duffy's blog PinmemberPaulo Zemek2:01 30 Nov '09  
GeneralMy vote of 2 [It was my fault, I have voted 5] PinmemberMiller46:08 28 Nov '09  
GeneralRe: My vote of 2 PinmemberPaulo Zemek6:29 28 Nov '09  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads.

PermaLink | Privacy | Terms of Use
Last Updated: 27 Nov 2009
Editor: Deeksha Shenoy
Copyright 2009 by Paulo Zemek
Everything else Copyright © CodeProject, 1999-2010
Web21 | Advertise on the Code Project