如何在C#中产生并捕获必要的异常?

时间:2011-02-15 20:47:58

标签: c# .net try-catch yield

我正在使用以下方法:

    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,我无法捕获利用这些方法的代码片段(如果有一个catch,则不能将yield放在try的主体内)。我知道我可以删除产量并简单地将我的孩子添加到一个集合中,但我很好奇有人会从这两种方法中捕获IOExceptions并仍然使用yield?

5 个答案:

答案 0 :(得分:5)

如何(第一部分):

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

同样的第二个。您不需要在该try块内屈服。如果这没有帮助,请写下您希望有效的任何代码,以便我们可以看到如果抛出异常,您打算做什么。

答案 1 :(得分:0)

该异常将通过GetDirectoriesGetFiles的调用抛出,因此您可try-catch而不是for-each

答案 2 :(得分:0)

你能不能在调用它们的代码中捕获之外的异常?

答案 3 :(得分:0)

你可以制作辅助方法,添加你的特殊错误处理酱:

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

   return subdirectories;
}

显然可以替换相关的电话。我当然认为你甚至想要在错误上屈服,但我谦卑地接受这种假设可能是错误的:)

答案 4 :(得分:0)

我会警告不要使用异常作为控制流的方法 - 如果您不确定目录或路径是否会返回有效结果,请先检查它 - 几乎所有这些异常都可以通过参数来防止检查,通常如下所示。

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;
    }
}

有足够的优化空间(并且已经成熟进行进一步分解),通常的注释适用于竞争条件,并且缺少保证在另一个线程上删除目录之前是否存在目录,所以现在你可以制作通过在Jon或xanatos建议的Get {Directories,Files}调用周围包装一个try / catch来更强大(编辑:我现在已经将其作为SafeIO包裹起来) - 但现在你只能抓住易受此影响的特定异常(IOExceptionDirectoryNotFoundException)并将其保留用于真正例外情况。