I've run ildasm to find that this:
using(Simple simp = new Simple())
{
Console.WriteLine("here");
}
generates IL code that is equivalent to this:
Simple simp = new Simple();
try
{
Console.WriteLine("here");
}
finally
{
if(simp != null)
{
simp.Dispose();
}
}
and the question is why the hell does it check null in the finally? The finally block will only be executed if the try block is executed, and the try block will only be executed if the Simple constructor succeeds (I.e. does not throw an exception), in which case simp will be non-null. (If there is some fear that some intervening steps might come between the Simple constructor and the beginning of the try block, then that would really be a problem because then an exception might be thrown that would prevent the finally block from executing at all.) So, why the hell?
Putting aside (please) the argument of whether the using statement is better than try-finally, I write my try-finally blocks as:
Simple simp = new Simple();
try
{
Console.WriteLine("here");
}
finally
{
simp.Dispose();
simp = null; // sanity-check in case I touch simp again
// because I don't rely on all classes
// necessarily throwing
// ObjectDisposedException
}
No, the finally block will ALWAYS be executed. You may not be getting the object from a new but from some other function that returns your object - and it might return NULL. using() is your friend!
dss539 was kind enough to suggest I include his note:
using(Simple simp = null)
is yet another reason that the expansion must check for null first.
using(Simple simp = null) is yet another reason that the expansion must check for null first.
MSDN on the using statement.
What I think is strange is that it doesn't expand to:
Simple simp = new Simple();
Simple __compilergeneratedtmpname = simp;
try
{
Console.WriteLine("here");
}
finally
{
if(__compilergeneratedtmpname != null)
{
__compilergeneratedtmpname.Dispose();
}
}
It appears that your comment:
"If there is some fear that some intervening steps might come between the Simple constructor and the beginning of the try block, then that would really be a problem because then an exception might be thrown that would prevent the finally block from executing at all."
is possibly dead on. See:
Atomicity & Asynchronous Exception Failures
I also want to note the issue(s) with WCF and using:
Avoiding Problems with the Using Statement and WCF Service Proxies which references:
Avoiding Problems with the Using Statement
The code must be translated this way to avoid possible NullReferenceException when disposing the object. As per C# language reference, the using statement accepts not only a local variable declaration as its first nonterminal resource_acquisition symbol, but any expression. Consider the following code:
DisposableType #object = null;
using(#object) {
// whatever
}
Clearly, unless null-conditional #object?.Dispose() in the finnaly block, an exception would ensue. The null check is superfluous only when the expression is of a non-nullable value type (non-nullable struct). And indeed, according to the aforementioned language reference it is absent in such case.
Related
I don't understand why the following code produces an error. Normally I can figure things out from the language specification, but in this case I don't understand the language specification.
This isn't causing problems in my code, by the way, I just want to understand the language.
Example:
bool success;
try
{
success = true;
}
catch
{
success = false;
}
finally
{
Console.WriteLine(success); // ERROR: Local variable 'success' might not be initialized before accessing
}
This behavior appears to be true of all versions of C#, but the quotes below are from C# Language Specification 5.0.
Section 5.3.3.14 Try-finally statements
The definite assignment state of v at the beginning of finally-block is the same as the definite assignment state of v at the beginning of stmt.
Here "beginning of stmt" refers to the beginning of the entire try-finally statement, i.e. just before try.
Section 5.3.3.15 Try-catch-finally statements
The following example demonstrates how the different blocks of a try statement (§8.10) affect definite assignment.
static void F() {
int i, j;
try {
goto LABEL;
// neither i nor j definitely assigned
i = 1;
// i definitely assigned
}
catch {
// neither i nor j definitely assigned
i = 3;
// i definitely assigned
}
finally {
// neither i nor j definitely assigned
j = 5;
// j definitely assigned
}
// i and j definitely assigned
LABEL:;
// j definitely assigned
}
Can anyone explain why success (in my example) or i (in the language spec example) are not definitely assigned at the beginning of the finally-block?
Simple reason is - There is no guarantee that the code in try or catch block will ever execute, before finally block.
ThreadAbort Exception can happen inside the try block, but before assignment executes.
Runtime code executes after exception is thrown but before code in catch blocks executes (Search for how exception handling works in .Net or "Structured Exception Handling").
Hence, code in try and catch block may never execute, before execution of finally block.
As Vikas said, exceptions can happen inside catch block too, passing control to the finally without running the whole catch block. There's no guarantee that either of the assignments actually completed.
Why design the language to make it easier to write bad code? Good code will catch only specific exceptions, or catch and log all but then rethrow the ones it doesn't recognize. Only bad code that catches and ignores all exceptions can even run into this case.
Besides, the fix is incredibly easy.
I was suggested during a code review to do
bool acquiredLock = false;
try {
Monitor.TryEnter(lockObject, 500, ref acquiredLock);
if (acquiredLock) {
// do something
}
else {
// fallback strategy
}
}
finally
{
if (acquiredLock)
{
Monitor.Exit(lockObject);
}
}
instead of the simpler
if (Monitor.TryEnter(lockObject, 500)) {
try {
// do something...
}
finally {
Monitor.Exit(lockObject);
}
} else {
// fallback strategy
}
What difference does it make? How can the first code not exhibit a bug where the second would exhibit a bug?
Assuming in your second snippet you'd actually call Monitor.Exit, the difference is explained in the documentation:
This overload always sets the value of the variable that is passed to the ref parameter lockTaken, even if the method throws an exception, so the value of the variable is a reliable way to test whether the lock has to be released.
In other words, with your second snippet, it might be feasible for an asynchronous exception to be thrown (e.g. the thread being aborted) after the lock has been acquired, but before the method has returned. Even with a finally block, you couldn't then easily tell whether or not you'd need to release the lock. Using the ref parameter, the "monitor acquired" and "ref parameter set to true" actions are atomic - it's impossible for the variable to have the wrong value when the method exits, however it exits.
As of C# 4, when targeting a platform supporting this overload, this is the code that the C# compiler generates too.
Your first snippet is exiting the monitor when the second is not. You want to release the monitor when you're done with the critical block.
Besides the entirely valid point about exiting that other posters have made... The documentation for the TryEnter method states that it can throw one of three exceptions, so technically, yes it could bomb your application under specific circumstances.
Even tough the method is named TryEnter, it actually throws exceptions, and you need to handle them properly. If it throws an exception and you don't handle it and release monitor, you can have a deadlock situation.
This maybe a bit too precautious, because if you look at exception that it actually throws, it will most probably throw them BEFORE trying to acquire lock. But this is an implementation detail and you can't be sure about it.
You can probably check how this method is implemented at http://referencesource.microsoft.com/ but, as I said, this is an implementation detail.
I read many threads about the using keyword in C#, but I couldn't find anyone with the same question.
Reading this interesting article, it says that the using statement is basically equivalent to a try/catch block:
MyResource myRes= new MyResource();
try
{
myRes.DoSomething();
}
finally
{
// Check for a null resource.
if (myRes!= null)
// Call the object's Dispose method.
((IDisposable)myRes).Dispose();
}
What really makes me going mad is that the object initialization myRes= new MyResource() is still outside of the try/catch block, so if something goes wrong during the initialization (oh, and it does!) I have no other way to handle it than using a normal try/catch block.
Is this correct or am I missing something? In my opinion, this makes the sense of the using statement partially useless.
I also tried something like this:
using (MyResource myRes)
{
myRes = new MyResource();
myRes.DoSomething();
}
but the compiler don't like this, so it is not possible to bring the initialization inside of the try block.
This seems so strange to me that I think that I must be missing something. Could anyone explain me the reasons behind this?
Well if the constructor fails, the exception will be thrown instead of the reference being returned - so the calling code has nothing to dispose.
Basically, constructors need to be careful. If an exception is thrown in an exception, the constructor needs to make sure no resources are leaked, because nothing else is going to get a chance to clean up.
I am use using to guarantee the resource cleanup. This is fine for the simple block of code.
If I have a method which I need to pass the variable inside the using, can I still guarantee resource clean up?
for example,
using ( FileStream fs = -----)
{
SomeMethod(fs);
}
Yes. using(){} is syntactic sugar, and it will expand your code to this:
FileStream fs = -----;
try {
SomeMethod(fs);
} finally {
if (fs != null)
((IDisposable)fs).Dispose();
}
finally blocks are guaranteed to execute whether an exception is thrown or not. The only time they wouldn't be executed is in the case of a severe runtime failure, such as a stack overflow, out of memory exception, or a crash in the runtime itself.
fs's Dispose() method will be invoked at the end of using's code block.
Yes, it will be disposed.
See the examples on the using Statement on MSDN - the Font is created with passed in parameters.
I understand the point of "using" is to guarantee that the Dispose method of the object will be called. But how should an exception within a "using" statement be handled? If there is an exception, I need to wrap my "using" statement in a try catch. For example:
Lets say there is an exception created in the creation of the object inside the using parameter
try
{
// Exception in using parameter
using (SqlConnection connection = new SqlConnection("LippertTheLeopard"))
{
connection.Open();
}
}
catch (Exception ex)
{
}
Or an Exception within the using scope
using (SqlConnection connection = new SqlConnection())
{
try
{
connection.Open();
}
catch (Exception ex)
{
}
}
It seems like if I already need to handle an exception with a try catch, that maybe I should just handle the disposing of the object as well. In this case the "using" statement doesn't seem to help me out at all. How do I properly handle an exception with "using" statement? Is there a better approach to this that I'm missing?
SqlConnection connection2 = null;
try
{
connection2 = new SqlConnection("z");
connection2.Open();
}
catch (Exception ex)
{
}
finally
{
IDisposable disp = connection2 as IDisposable;
if (disp != null)
{
disp.Dispose();
}
}
Could the "using" keyword syntax be a little more sugary...
It sure would be nice to have this:
using (SqlConnection connection = new SqlConnection())
{
connection.Open();
}
catch(Exception ex)
{
// What went wrong? Well at least connection is Disposed
}
Because you would be 'hiding' extra functionality inside an unrelated keyword.
However you could always write it this way
using (...) try
{
}
catch (...)
{
}
And this way the line represents your intentions -- a using statement that is also a try
using Has nothing to do with error handling. It's shorthand for "call Dispose when you leave this block." Your second code example is perfectly acceptable... why mess with what works?
The using block is just syntactic sugar for a try-finally block. If you need a catch clause, just use a try-catch-finally:
SqlConnection connection;
try
{
connection = new SqlConnection();
connection.Open();
}
catch(Exception ex)
{
// handle
}
finally
{
if (connection != null)
{
connection.Dispose();
}
}
Yes, this is more code than your theoretical "using-catch"; I judge the language developers didn't consider this a very high priority, and I can't say I've ever felt its loss.
I've had places where this would be useful. But more often, when I want to do this it turns out that the problem is in my design; I'm trying to handle the exception in the wrong place.
Instead, I need to allow it to go up to the next level — handle it in the function that called this code, rather than right there.
An interesting idea, but it would make the following kinda confusing:
using (SqlConnection connection = new SqlConnection())
using (SqlCommand cmd = new SqlCommand())
{
connection.Open();
}
catch(Exception ex)
{
// Is connection valid? Is cmd valid? how would you tell?
// if the ctor of either throw do I get here?
}
You are mixing concerns in my opinion. Resource management (i.e. disposale of objects) is completely separated from exception handling. The one-to-one mapping that you describe in your question is just a very special case. Usually exception handling will not happen in the same place as the using scope ends. Or you might have multiple try-catch regions inside a using block. Or ...
I recommend you use example #1 and #2 combined. The reason is your using statement could read a file, for instance, and throw an exception (i.e File Not Found). If you don't catch it, then you have an unhandled exception. Putting the try catch block inside the using block will only catch exceptions that occur after the using statement has executed. A combination of your example one and two is best IMHO.
The purpose of the "using" statement is to ensure that some type of cleanup operation will occur when execution exits a block of code, regardless of whether that exit is via fall-through, an exception, or return. When the block exits via any of those means, it will call Dispose on the parameter of using. The block exists, in some sense, for the benefit of whatever is being specified as the using parameter, and in general that thing won't care why the block was exited.
There are a couple of unusual cases for which provisions might be helpful; their level of additional utility would be well below that provided by having using in the first place (though arguably better than some other features the implementers see fit to provide):
(1) There is a very common pattern in constructors or factories of objects which encapsulate other IDisposable objects; if the constructor or factory exits via an exception, the encapsulated objects should be Disposed, but if it exits via return they should not. Presently, such behavior must be implemented via try/catch, or by combining try/finally with a flag, but it would IMHO be helpful if there were either a variation of using which would only call Dispose when it exited via exception, or else a keep using statement which would null out the temporary employed by the using statement to hold the object which needed disposal (since using cannot be preceded by an identifier, such a feature could be added in a manner somewhat analogous to yield return).
(2) In some cases, it would be helpful if the finally keyword extended to accept an Exception argument; it would hold the exception which caused the guarded clause to exit (if any), or null if the guarded clause exits normally (via return or fall-through), and if the using block could make use of interface IDisposeExOnly {void DisposeEx(Exception ex);} and Interface IDisposeEx : IDisposable, IDisposableExOnly {} (at compile-time, selected DisposeEx() if implemented, or Dispose() otherwise). This could allow transaction-based objects to safely support auto-commit (i.e. perform the commit if the passed-in exception is null, or roll-back if non-null) and would also allow for improved logging in situations where Dispose fails as a consequence of a problem within the guarded clause (the proper thing would be for Dispose to throw an exception which encapsulates both the exception that was pending when it was called, and the exception that occurred as a consequence, but there's presently no clean way to do that).
I don't know if Microsoft will ever add such features; the first, and the first part of the second, would be handled entirely at the language level. The latter part of the second would be at the Framework level.