Define and add `FileSystemError` enum and matching property to IOException
#926 opened on Dec 22, 2018
Repository metrics
- Stars
- (17,886 stars)
- PR merge metrics
- (Avg merge 12d 11h) (661 merged PRs in 30d)
Description
(similar to dotnet/corefx#34220)
Scenario: I want to create and write some default data into a file unless it already exists.
A naive implementation would be:
if (!File.Exists(path))
{
using (var fileStream = File.Open(path, FileMode.CreateNew))
{
// ...
}
}
The problem with this is that I'm accessing the file system at 2 points in time. As @jaredpar has taught me, File.Exists is evil. There's no guarantee that because File.Exists returned false, the file still won't exist when calling File.Open.
To be robust, we should just call File.Open and catch the exception it throws in case the file already exists. The problem is that it throws System.IO.IOException with a message of "The file already exists". There is no specific exception type for this scenario. At first it would seem that the only thing we can do is catch the exception depending on its message string (which is a terrible idea), but luckily, there is a specific HResult for this failure, leaving us with:
Stream fileStream = null;
try
{
fileStream = File.Open(path, FileMode.CreateNew);
}
catch (IOException e) when (e.HResult == -2147024816) // FILE_EXISTS
{
}
if (fileStream != null)
{
using (fileStream)
{
// ...
}
}
This works OK but makes the code seem unreadable and maybe even brittle because we're depending on a magic constant that comes somewhere from the Windows API. I'm not sure if this code works outside of Windows at all, but even if it does, it's definitely not obvious.
Please add a dedicated exception type for this kind of failure.