Hello everyone,
I understand there is no need to call Dispose explicitly when dealing with StreamReader/StreamWriter object instances since GC will take care of it in Finalizer method.
My question is, I want to know the benefits and potential issues of using "using" statement to deal with StreamReader/StreamWriter.
thanks in advance,
George
George GeorgePosted Aug 26, 2008, 9:41 AM
Thanks for clarification. :-)
regards,
George
Ryan AlfordPosted Aug 26, 2008, 9:01 AM
George GeorgePosted Aug 25, 2008, 10:31 PM
Hi Ryan,
Good to see you participation. Could you explain your reasons why put using block inside try/catch please? :-)
regards,
George
Ryan AlfordPosted Aug 25, 2008, 5:04 PM
personally, I put the resource in a using block which is inside a try/catch..... ie:
try
{
using(.....)
{
}
}
catch
{
}
I haven't had anybody complain about performance yet.
George GeorgePosted Aug 25, 2008, 1:45 AM
Thanks, so your point is put resource is using block will enable it to be reclaimed more quickly? Is that what you mean?
regards,
George
zolPosted Aug 20, 2008, 8:41 PM
Right when the control leaves the using block, the memory that was referenced by these objects can be cleaned up for use. And as you said, it doesn't require an explicit close method call which makes them i think so nice to use them.
George GeorgePosted May 29, 2008, 1:29 AM
Thanks Dave,
Question answered.
regards,
George
DavePosted May 28, 2008, 9:09 AM
then you only need the one try/catch.
If you want to catch any exception at all thrown in a using block, then that has to be nested in a try/catch. And, as discussed, that results in two try/catches.
So, in the final round up, if you are concerned about a possible exception in the finally part of a try/catch, then you would need to nest that try/catch and it would be the exact same as if you nested a using.
So it all comes down to whether you are happy that an exception is unlikely to be thrown in the finally block.
That might be something you want to research. I have no idea what the likelihood of exceptions being thrown due to those two operations are. Closing the database connection could conceivably run into problems from time to time. Perhaps someone with more experience than me could answer that. At this stage, I am only a student.
George GeorgePosted May 28, 2008, 6:37 AM
Thanks Dave,
I agree with you. Since the discussion is lengthy, I want to finally confirm with you that to achieve the same effect, you only need 2 try-catch block and using block needs 3 try-catch blocks. So, your code is more efficient. Correct?
regards,
George
DavePosted May 28, 2008, 4:29 AM
Basically, the only difference is that I am calling Dispose() manually.
I re-iterate, you need to nest the using block in a try/catch to catch any exceptions thrown in that block. This is inefficient, if the alternative is using just the one try/catch.
try/catch comes with a lot of overhead.
George GeorgePosted May 26, 2008, 3:47 AM
Thanks Bechir,
1.
You mentioned "if you dispose this object by forcing the GC to clean it then after this line u make use of it by carelessness u will recieve a null reference exception". What do you mean "forcing the GC to clean it"? Invoking GC.Collect explicitly or you mean call Dispose method?
2.
"to avoid this problem" -- because of the lifetime of the variable in the using block does not expand beyond the using block?
regards,
George
Bechir BejaouiPosted May 25, 2008, 5:59 PM
George GeorgePosted May 25, 2008, 7:24 AM
Hi Bechir,
You mean using block only catches NullreferenceException? It should catch no exception and just do a finally block execution no matter what happens (normally or exception thrown) in the using block. Any comments?
regards,
George
Bechir BejaouiPosted May 25, 2008, 6:54 AM
George GeorgePosted May 25, 2008, 5:42 AM
Thanks Dave,
Your reply is really great!
Two more comments,
1.
You mentioned below,
--------------------
it will actually catch an exception
catch
{
...handle exceptions
}
--------------------
I think you mean your code only catch a specific exception, but actually you are using catch clause and no exception type is assigned with catch -- it means catch all exceptions, not one specific type of exception. So, your code is the same as the code generated by using block.
2.
"need an outer try/catch statement" -- I agree with this solution. But I think it is of the same effect of using try/catch block inside the finally block to wrap the statement like Dispose. Any comments?
regards,
George
DavePosted May 21, 2008, 6:55 PM
using(IDBConnection conn = new SQLiteDBConnection ())
{
…connect and do stuff
…exception was thrown here
}
An exception was being thrown in one case due to a dodgy SQL statement. This was within the using block. But nothing was catching the exception. So, even though there was a try catch statement hidden by using, it wasn't catching anything. I then discovered that I had to embed the whole using block in a try/catch, if I wanted to catch that exception.
So, to answer your question, a using block doesn't actually catch anything. All it is good for his closing and disposing of whatever object you are using (whether it is a database connection or an input stream).
My code is only more efficient insofar as it will actually catch an exception.
try
IDBConnection conn = new SQLiteDBConnection ();
{
…any exceptions will be thrown here
}
catch
}
{
...handle exceptions
finally
{
conn.Close();
conn.Dispose();
}
However, it won't catch an exception thrown by any code in the finally part. That being the case, if you were worried about an exception being thrown in the "clean up" operations which are normally put in the finally block, then you should use an outer try catch.
With my way, you have a little more control over things and you can catch the lions share of exceptions with just the one try/catch. With a using block, to catch any exceptions at all, you need an outer try/catch statement. And that means a minimum of two try/catch blocks, rather than the single one that I use.
I hope this helps.
George GeorgePosted May 21, 2008, 10:46 AM
Thanks,
1.
From your reply, I learned two things which is really valuable.
- using block does not handle any exception in finally, e.g. Dispose/Close
- using block will catch all exception and not thrown again?
My understanding correct?
2.
I understand why you say using try-catch block together with using block is less efficient. But what is your code to be more efficient than using block? Could you show here please?
regards,
George
DavePosted May 21, 2008, 8:49 AM
Now, although a try/catch is hidden by the using structure, you still need to embed it in another try/catch to catch the exception. For example:
try
{
using(sr = new StreamReader())
{
do stuff…
}
catch
{
handle exception
}
try
{
try
{
srObject.Open() ...
read stuff etc...
}
catch
{
any exceptions ...
}
finally
{
srObject.close()
srObject.dispose()
}
catch
{
handle exception...
}
As you can see, you are now using two try/catches instead of just the one. That is why I just use the one try/catch. Same result, less overhead. And usually, I am not concerned about an exception being thrown by the Close() or Dispose() operations.
Exception handling is just another cost/benefit decision a programmer has to make. It adds stability, but also overhead. So I guess it is a decision to be made on the case by case basis.
George GeorgePosted May 21, 2008, 5:06 AM
Great Dave!
1.
Good point! I understand C# compiler will expand code of using block to catch and finally. I am interested to learn that what types of exception in the expanded code of using block will catch? All types of exceptions or some specific exception types (e.g. IO or Stream class related)?
2.
Any differences between your code and C# compiler expanded code for using block? I think they are the same, why do you think your code is of better performance?
regards,
George
George GeorgePosted May 21, 2008, 5:02 AM
I have a further question. If there is exception, and in both exception handler and finally block, I do not call Close/Dispose explicitly, will Dispose/Close be called automatically during exception (e.g. similar to during stack unwinding in C++)? Or we have to wait for GC to call Finalize?
regards,
George
DavePosted May 20, 2008, 8:17 PM
try
{
srObject.Open() ...
read stuff etc...
}
catch
{
any exceptions ...
}
finally
{
srObject.close()
srObject.dispose()
}
You can catch the exceptions with just the one try/catch doing it that way.
Scott LyslePosted May 20, 2008, 1:28 PM