dotnet/runtime

Define and add `FileSystemError` enum and matching property to IOException

Open

#926 geöffnet am 22. Dez. 2018

Auf GitHub ansehen
 (64 Kommentare) (21 Reaktionen) (0 zugewiesene Personen)C# (5.445 Forks)batch import
api-suggestionarea-System.IOhelp wanted

Repository-Metriken

Stars
 (17.886 Stars)
PR-Merge-Metriken
 (Durchschn. Merge 12T 11h) (661 gemergte PRs in 30 T)

Beschreibung

(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.

Contributor Guide