Do you know series of posts titled Interview Question of the Week on a SQL Authority blog? If not or if you don't know this blog at all you have to catch up. I learned a lot of from this series so I decided to start publishing something similar but to focus more on .NET and programming.
This is a first post from series which I called Interview Questions for Programmers by MK and in which I'm going to publish questions that I'd ask if I were a recruiter. Of course they are somehow based on my experience as a participant of many interviews.
Question #1
What is a meaning of using statement in the code below? What would you do if using keyword did not exist?
In this example using statement is used to properly release resources (to call Dispose method) that are owned by an object of a class that implements IDisposable interface. It is a syntactic sugar and could be replaced by using try/finally block in the following way:
This is a first post from series which I called Interview Questions for Programmers by MK and in which I'm going to publish questions that I'd ask if I were a recruiter. Of course they are somehow based on my experience as a participant of many interviews.
Question #1
What is a meaning of using statement in the code below? What would you do if using keyword did not exist?
using(var file = File.OpenWrite(path)) { //... }Answer #1
In this example using statement is used to properly release resources (to call Dispose method) that are owned by an object of a class that implements IDisposable interface. It is a syntactic sugar and could be replaced by using try/finally block in the following way:
var file = File.OpenWrite(path); try { //... } finally { if(file != null) file.Dispose(); }
Tak, bardzo popularne pytanie na rekrutacjach.
ReplyDeleteMoim zdaniem w odpowiedzi powinna się jeszcze pojawić klamra na początku oraz końcu, która ograniczy zasięg zmiennej file.
Hi, on the one hand you are right because C# compiler will add extra curly braces to limit the scope of variables within "using" statement (in this case "file" variable). However, personally I don't use extra curly braces in my code so I decided not to include them in the answer above. I think that if methods are short (what is a good practice) additional effort to limit the scope of variables is not needed.
ReplyDeleteThere is a bug the sample code above. OpenWrite method call should be placed inside the try-fnally block because there is a possibility that "something bad" will happen just after OpenWrite method acquires a file handle.
ReplyDeleteArek, what do you mean by "something bad"? If it is a crash of a program (for example caused by OutOfMemoryException), the execution of finally block is not guaranteed anyway.
ReplyDeleteI think that it is not wrong to call OpenWrite inside try-finally block (as you suggested) but I wanted to make my answer consistent with a code generated by a compiler. If you try to examine using statement with ILSpy you will see something like in my answer. The only difference will be the lack of curly braces (see the first comment).
Wow - thank you for pointing it out. I was not aware that using statement is not safe!
ReplyDeleteConsider the following example:
class Program
{
static void Main(string[] args)
{
string path = "whatever";
using (var example = Example.AllocExternalResources(path))
{
}
}
}
public class Example : IDisposable
{
private FileStream _stream;
private Example(FileStream stream)
{
_stream = stream;
}
public void Dispose()
{
if (_stream != null)
{
_stream.Dispose();
}
}
public static Example AllocExternalResources(string path)
{
var stream = File.OpenWrite(path);
// some code that throws an exception
return new Example(stream);
}
}
The Dispose() method is not called!
That's why I always put statements that are creating disposable objects inside try blocks.
In your example 'Dispose' method will not be called even if you call 'AllocExternalResources' inside 'try' block. The exception will cause that 'AllocExternalResources' will return nothing and 'example' variable will be 'null' in the 'finally' block. And because of that 'Dispose' will not be called.
ReplyDeleteOpps, my mistake. Thanks!
ReplyDelete