Как я могу выдать, а также поймать необходимые исключения в C #? - PullRequest
1 голос
/ 15 февраля 2011

У меня есть следующий метод, над которым я работаю:

    private IEnumerable<TreeNode> GetChildNodes(TreeNode parent)
    {
        string path = parent.Tag.ToString();

        // Add Directories
        string[] subdirs = Directory.GetDirectories(path);

        foreach (string subdir in subdirs)
        {
            yield return GetChildNode(subdir);
        }

        // Add Files
        string[] files = Directory.GetFiles(path);

        foreach (string file in files)
        {
            var child = GetChildNode(file);
            fileNodeMap[file] = child;
            yield return child;
        }
    }

Это прекрасно работает, за исключением того, что Directory.GetDirectories () и Directory.GetFiles () могут генерировать исключения, которые я хочу перехватить.

Я не могу поймать фрагменты кода, которые используют эти методы, из-за моего использования yield (выходы не могут быть помещены в тело try, если есть перехват). Я знаю, что мог бы удалить доходность и просто добавить своих детей в коллекцию, но мне любопытно, как кто-то мог бы получить исключения IOException от обоих этих методов и все еще использовать урожай?

Ответы [ 5 ]

5 голосов
/ 15 февраля 2011

Как насчет чего-то вроде (для первой части):

string[] subdirs;
try
{
    subdirs = Directory.GetDirectories(path);
}
catch (IOException e)
{
    // Do whatever you need here
    subdirs = new string[0];
}

И аналогично для второй.Вам не нужно уступать в этом блоке try.Если это не поможет, пожалуйста, напишите любой код, который вы бы хотели бы, чтобы был действительным, чтобы мы могли видеть, что вы планируете делать, если выдается исключение.

0 голосов
/ 16 февраля 2011

Я бы предостерег от использования исключений в качестве метода потока управления - если вы не уверены, что каталог или путь вернут верный результат, сначала проверьте его - почти все эти исключения могут быть предотвращены аргументом проверка, что-то, как правило, как показано ниже.

private IEnumerable<TreeNode> GetChildNodes(TreeNode parent)
{
    string path = parent.Tag.ToString();

    if (String.IsNullOrEmpty (path) || String.IsNullOrWhiteSpace (path))
        yield break;

    // I'm not aware of a constant/enum for the maximum allowed path length here :(
    if (path.Length > 260 || path.Any (Path.GetInvalidPathChars ().Contains))
        yield break;

    if (!Directory.Exists (path))
        yield break;

    Func<string[], Func<string[],string>,> SafeIO = (fn, arg) => {
        try {
            return fn (p);
        } catch (IOException) {
            return new string[0];
        }
    };

    // Add Directories
    string[] subdirs = SafeIO (Directory.GetDirectories, path);
    foreach (string subdir in subdirs)
        yield return GetChildNode(subdir);

    // Add Files
    string[] files = SafeIO (Directory.GetFiles, path);
    foreach (string file in files) {
        var child = GetChildNode(file);
        fileNodeMap[file] = child;
        yield return child;
    }
}

Там достаточно места для оптимизации (и созревания для дальнейшей декомпозиции), и обычные комментарии относятся к условиям гонки и отсутствию гарантии для проверки, существует ли каталог перед его удалением в другом потоке, так что теперь вы можете сделать это более надежно, заключая в себе попытку / ловушку вокруг вызовов Get {Directories, Files}, как предложили Джон или Ксанатос (РЕДАКТИРОВАТЬ: и что я теперь обернут здесь как SafeIO) - но теперь вы можете поймать только конкретное исключение который восприимчив к этому (IOException или DirectoryNotFoundException) и резервирует его для действительно исключительных случаев.

0 голосов
/ 16 февраля 2011

Вы можете создать вспомогательные методы, которые добавят ваш специальный соус для обработки ошибок:

private string[] GetSubdirectoriesWithSpecialSauce(string path)
{
   string[] subdirectories;
   try
   {
       subdirectories = Directory.GetDirectories(path);
   }
   catch (IOException ioe)
   {
       ShutdownWOPR();
       CallDrFalken();
   }

   return subdirectories;
}

И, очевидно, заменит соответствующие вызовы.Я, конечно, предполагал, что вы хотели уступить даже на ошибках, но я скромно признаю, что это предположение может быть неверным:)

0 голосов
/ 15 февраля 2011

Не могли бы вы перехватить исключения за пределами в коде, который их вызывает?

0 голосов
/ 15 февраля 2011

Исключение будет вызвано вызовом GetDirectories и GetFiles, поэтому вы можете try-catch ИХ вместо for-each,

...