HiveBrain v1.2.0
Get Started
← Back to all entries
debugcsharpMinor

Simplifying exception handling on Enumerators

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
handlingexceptionsimplifyingenumerators

Problem

I have a files search function that iterates over a given directory until a given depth is reached and returns the found files. I did this via the Enumerate methods of the Directory class and yield return the results. Since it's very likely that I hit a directory that I can't access (e.g. system directories) or generate a too long path (if the depth is large), I have to catch the exceptions from these cases. However since I can't use yield in try/catch statements, I find my code pretty bloated, because I have to seperate the critical method calls from the rest.

Is there a better/shorter way to do this, or are there best practices for that case?

private IEnumerable SearchSubdirs(string currentDir, int currentDepth) {

    IEnumerable exeFiles;
    try {
        exeFiles = Directory.EnumerateFiles(currentDir, "*.exe");
    }
    catch (UnauthorizedAccessException uae) {
        Debug.WriteLine(uae.Message);
        yield break;
    }
    catch (PathTooLongException ptle) {
        Debug.WriteLine(ptle.Message);
        yield break;
    }

    foreach (string currentFile in exeFiles) {

        // Ignore unistaller *.exe files
        if (currentFile.IndexOf("unins", 0, StringComparison.CurrentCultureIgnoreCase) == -1) {
            yield return currentFile;
        }
    }

    if (currentDepth  subDirectories;
        currentDepth++;
        try {
            subDirectories = Directory.EnumerateDirectories(currentDir);
        }
        catch (UnauthorizedAccessException uae) {
            Debug.WriteLine(uae.Message);
            yield break;
        }
        catch (PathTooLongException ptle) {
            Debug.WriteLine(ptle.Message);
            yield break;
        }

        foreach (string subDir in subDirectories) {
            foreach (string file in SearchSubdirs(subDir, currentDepth)) {
                yield return file;
            }
        }
    }
}

Solution

I would use Linq methods to simplify the code. Also I've extracted 2 methods to simplify the main method. And please rename GetFilesWeAreLookingFor to whatever your find appropriate :).

private static IEnumerable GetFilesWeAreLookingFor(string currentDir)
{
    try
    {
        return Directory.EnumerateFiles(currentDir, "*.exe")
            .Where(fileName => fileName.IndexOf("unins", 0, StringComparison.CurrentCultureIgnoreCase) == -1);
    }
    catch (UnauthorizedAccessException uae)
    {
        Debug.WriteLine(uae.Message);
    }
    catch (PathTooLongException ptle)
    {
        Debug.WriteLine(ptle.Message);
    }
    return Enumerable.Empty();
}

private IEnumerable GetNestedFiles(string currentDir, int nestedDepth)
{
    try
    {
        return Directory.EnumerateDirectories(currentDir)
            .SelectMany(subDirectory => SearchSubdirs(subDirectory, nestedDepth));
    }
    catch (UnauthorizedAccessException uae)
    {
        Debug.WriteLine(uae.Message);
    }
    catch (PathTooLongException ptle)
    {
        Debug.WriteLine(ptle.Message);
    }
    return Enumerable.Empty();
}

private IEnumerable SearchSubdirs(string currentDir, int currentDepth)
{
    IEnumerable filesWeAreLookingFor = GetFilesWeAreLookingFor(currentDir);

    if (currentDepth < _maxDepth)
        filesWeAreLookingFor = filesWeAreLookingFor.Concat(GetNestedFiles(currentDir, currentDepth + 1));

    return filesWeAreLookingFor;
}

Code Snippets

private static IEnumerable<string> GetFilesWeAreLookingFor(string currentDir)
{
    try
    {
        return Directory.EnumerateFiles(currentDir, "*.exe")
            .Where(fileName => fileName.IndexOf("unins", 0, StringComparison.CurrentCultureIgnoreCase) == -1);
    }
    catch (UnauthorizedAccessException uae)
    {
        Debug.WriteLine(uae.Message);
    }
    catch (PathTooLongException ptle)
    {
        Debug.WriteLine(ptle.Message);
    }
    return Enumerable.Empty<string>();
}

private IEnumerable<string> GetNestedFiles(string currentDir, int nestedDepth)
{
    try
    {
        return Directory.EnumerateDirectories(currentDir)
            .SelectMany(subDirectory => SearchSubdirs(subDirectory, nestedDepth));
    }
    catch (UnauthorizedAccessException uae)
    {
        Debug.WriteLine(uae.Message);
    }
    catch (PathTooLongException ptle)
    {
        Debug.WriteLine(ptle.Message);
    }
    return Enumerable.Empty<string>();
}

private IEnumerable<string> SearchSubdirs(string currentDir, int currentDepth)
{
    IEnumerable<string> filesWeAreLookingFor = GetFilesWeAreLookingFor(currentDir);

    if (currentDepth < _maxDepth)
        filesWeAreLookingFor = filesWeAreLookingFor.Concat(GetNestedFiles(currentDir, currentDepth + 1));

    return filesWeAreLookingFor;
}

Context

StackExchange Code Review Q#23494, answer score: 5

Revisions (0)

No revisions yet.