Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chapter 09. Disposing of file resources #90

Open
Dreamoochy opened this issue Jul 5, 2022 · 3 comments
Open

Chapter 09. Disposing of file resources #90

Dreamoochy opened this issue Jul 5, 2022 · 3 comments

Comments

@Dreamoochy
Copy link

There's a code on pp. 383, 384:

try
{
  ...
  xmlFileStream = File.Create(xmlFile);
  xml = XmlWriter.Create(xmlFileStream, new XmlWriterSettings { Indent = true });
  ...
}
...
finally
{
  if (xml != null)
  {
    xml.Dispose();
    WriteLine("The XML writer's unmanaged resources have been disposed.");
    if (xmlFileStream != null)
    {
      xmlFileStream.Dispose();
      WriteLine("The file stream's unmanaged resources have been disposed.");
    }
  }
}

Why is xmlFileStream disposal nested in (xml != null) check? If I'm not mistaken, theoretically an exception can occur inside XmlWriter.Create. In that case xml will remain null, therefore xmlFileStream will not be disposed.

@markjprice
Copy link
Owner

Good point. I will move it outside the if statement. I have added an errata:
https://github.com/markjprice/cs10dotnet6/blob/main/errata.md#page-384---disposing-of-file-resources

@Dreamoochy
Copy link
Author

Dreamoochy commented Jul 6, 2022

Some addition. In section "Simplifying disposal by using the using statement" (pp. 385,386) there are two code blocks:

using (FileStream file2 = File.OpenWrite(Path.Combine(path, "file2.txt")))
{
  using (StreamWriter writer2 = new StreamWriter(file2))
  {
    ...
  } // automatically calls Dispose if the object is not null
} // automatically calls Dispose if the object is not null

and simplified variant:

using FileStream file2 = File.OpenWrite(Path.Combine(path, "file2.txt"));
using StreamWriter writer2 = new(file2);
...

They are actually not equal. The difference is in a life-scope of the variables. In the first case file2 and writer2 are available only within their using { ... } blocks. They are automatically closed and disposed there. It would be impossible to use them farther, and they would not cause further errors.

In the second case both variables live within entire outer code block even if not used anymore. So it might be necessary to manually perform some operations. E.g. if someone wants to read "file2.txt" after writing, they will need to explicitly close the streams:

writer2.Close();
file2.Close();
File.ReadAllText(Path.Combine(path, "file2.txt"));

I'm sure you're aware of this behaviour, but it took some time for me to realize why seemingly proper code causes exceptions.

@Dreamoochy
Copy link
Author

Dreamoochy commented Jul 6, 2022

One more thing about using statement. In section "Compressing streams" (pp. 386+) there are code snippets like

Stream decompressor = new GZipStream(file,CompressionMode.Decompress);
using (decompressor)
{
...
}

In the documentation MS writes:

You can instantiate the resource object and then pass the variable to the using statement, but this isn't a best practice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants