Code Review Stack Exchange is a question and answer site for peer programmer code reviews. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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<string> SearchSubdirs(string currentDir, int currentDepth) {

    IEnumerable<string> 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 < maxDepth) {
        IEnumerable<string> 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;
            }
        }
    }
}
share|improve this question
up vote 4 down vote accepted
+50

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<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;
}
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.