Lets go for another code trivia, it’s business as usual, you just need to find what’s wrong with the following code:
static void Main(string[] args) { using (var file = new FileStream("test", FileMode.Create) { WriteTimeout = 1 }) { file.WriteByte(0); } }
TIP: There’s something very wrong with this specific code and there’s also another subtle problem that arises due to how the code is structured.
As explained in the comments, the using statement expands to the following code leading to the FileStream object never getting disposed because the finally is never executed.
FileStream file = new FileStream("test", FileMode.Create) { WriteTimeout = 1 }; try { file.WriteByte(0); } finally { if (file != null) ((IDisposable)file).Dispose(); }
With this in mind, one could be tempted to use a custom try/finally block for handling this situation. Something like this:
FileStream file = null; try { file = new FileStream("test", FileMode.Create) { WriteTimeout = 1 }; file.WriteByte(0); } finally { if (file != null) file.Dispose(); }
However this suffers from the same problem but due to a different cause. Even though the constructor for the object is called inside the try clause the object initializer syntax prevents it from being assigned to the file
variable before all properties have been initialized, leading to the file stream still not being disposed.
The expansion caused by the object initializer syntax is shown in the next sample of code:
FileStream file = null; try { FileStream compilerGenerated = new FileStream("test", FileMode.Create); compilerGenerated.WriteTimeout = 1; file = compilerGenerated; file.WriteByte(0); } finally { if (file != null) file.Dispose(); }
Basically, you need to be careful with using blocks where the resource initialization expression may throw an exception and you also need to pay careful attention on the subtleties of using object initializer syntax.