简体   繁体   中英

Getting an error with .Where using a lambda expression in a foreach loop for invalid arguments

I am busy creating a file/folder indexing Windows Forms Application in VS2010(Assignment for college). For testing purposes the file/folder indexing class is in a console application

I use the following to go through folders, it runs fine and writes to file all the folder names in the specified drive. I've thrown this together from mainly the msdn resources(used the recursive method), and modified since it didn't include getting folder names.

I want to exclude certain folders, and decided to use a lambda expression and List with list of words will be fastest, although I could just place a loop that goes through an array with an if comparison, but to my mind this would be slower(not that I understand enough about intricate workings in c#). I've had a brief look at lambda expressions to see if I can't fix it myself.

Here is my code working without any folder exclusion

class Program
{
    static System.Collections.Specialized.StringCollection log = new System.Collections.Specialized.StringCollection();
    private static List<string> _excludedDirectories = new List<string>() { "Windows", "AppData", "$WINDOWS.~BT", "MSOCache", "ProgramData", "Config.Msi", "$Recycle.Bin", "Recovery", "System Volume Information", "Documents and Settings", "Perflogs" };

    //method to check
    static bool isExcluded(List<string> exludedDirList, string target)
    {
        return exludedDirList.Any(d => new DirectoryInfo(target).Name.Equals(d));
    }

    static void Main()
    {

        string[] drives = {"C:\\"};

        foreach (string dr in drives)
        {
            DriveInfo di = new System.IO.DriveInfo(dr);

            // Here we skip the drive if it is not ready to be read. 
            if (di.IsReady)
            {
                DirectoryInfo rootDir = di.RootDirectory;
                WalkDirectoryTree(rootDir);
            }
            else
            {
                Console.WriteLine("The drive {0} could not be read", di.Name);
                continue;
            }
        }

        // Write out all the files that could not be processed.
        Console.WriteLine("Files with restricted access:");
        foreach (string s in log)
        {
            Console.WriteLine(s);
        }
        // Keep the console window open in debug mode.
        Console.WriteLine("Press any key");
        Console.ReadKey();
    }

    static void WalkDirectoryTree(System.IO.DirectoryInfo root)
    {
        FileInfo[] files = null;
        DirectoryInfo[] subDirs = null;
        StreamWriter filex = new System.IO.StreamWriter("test.txt", true);

        if (filex != null)
        {
            filex.Close();
        }

        // Process all the folders directly under the root 
        try
        {
            subDirs = root.GetDirectories();
        }// This is thrown if even one of the folders requires permissions greater than the application provides. 
        catch (UnauthorizedAccessException e)
        {
            log.Add(e.Message);
        }
        catch (System.IO.DirectoryNotFoundException e)
        {
            Console.WriteLine(e.Message);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }

        // Process all the files directly under the root 
        try
        {
            files = root.GetFiles("*.*");
        }// This is thrown if even one of the files requires permissions greater than the application provides. 
        catch (UnauthorizedAccessException e)
        {
            log.Add(e.Message);
        }
        catch (System.IO.DirectoryNotFoundException e)
        {
            Console.WriteLine(e.Message);
        }
        catch(Exception e)
        {
            Console.WriteLine(e.Message);
        }

        if (files != null)
        {
            filex = new StreamWriter("test.txt", true);
            foreach (FileInfo fi in files)
            {
                // In this example, we only access the existing FileInfo object. If we 
                // want to open, delete or modify the file, then 
                // a try-catch block is required here to handle the case 
                // where the file has been deleted since the call to TraverseTree().
                Console.WriteLine(fi.FullName);
                filex.WriteLine(fi.FullName);
            }
            filex.Close();
        }

        if (subDirs != null)
        {
            //var filteredDirs = Directory.GetDirectories(root.Name).Where(d => !isExcluded(_excludedDirectories, d));
            foreach (DirectoryInfo subds in subDirs)
            {
                filex = new StreamWriter("test.txt", true);
                Console.WriteLine(subds.FullName);
                filex.WriteLine(subds.FullName);
                filex.Close();

                foreach (DirectoryInfo dirInfo in subDirs)
                {
                    // Resursive call for each subdirectory.
                    WalkDirectoryTree(dirInfo);
                }
            }
            filex.Close();// Because at end filestream needs to close
        }
    }
}

So I tried incorporating the .Where(d => !isExcluded(_excludedDirectories, d)) into my loop:

if (subDirs != null)
        {
            //var filteredDirs = Directory.GetDirectories(root.Name).Where(d => !isExcluded(_excludedDirectories, d));
            foreach (DirectoryInfo subds in subDirs.Where(d => !isExcluded(_excludedDirectories, d)))
            {
                filex = new StreamWriter("test.txt", true);
                Console.WriteLine(subds.FullName);
                filex.WriteLine(subds.FullName);
                filex.Close();

                foreach (DirectoryInfo dirInfo in subDirs)
                {
                    // Resursive call for each subdirectory.
                    WalkDirectoryTree(dirInfo);
                }
            }
            filex.Close();// Because at end filestream needs to close
        }

PROBLEM: I get an error from after the exclamation saying "The best overloaded method match has some invalid args..." What should I do/change, should I take the simpler route and use a loop and if statement in my loop that writes the folder names? Because I also understand how to do that. And remember the way I'm currently doing(trying to at least) is because I thought it would be more optimised/faster. If it doesn't make such a great difference, let me know and I will use the way I know.

My guess is that I'm doing a bad thing by trying to put a .where there in the foreach, and I realise why it is or might be.

I've also tried:

if (subDirs != null)
        {
            //var filteredDirs = Directory.GetDirectories(root.Name).Where(d => !isExcluded(_excludedDirectories, d));
            foreach (DirectoryInfo subds in subDirs)
            {
              if ((d => !isExcluded(_excludedDirectories, d)))
              {
                filex = new StreamWriter("test.txt", true);
                Console.WriteLine(subds.FullName);
                filex.WriteLine(subds.FullName);
                filex.Close();

                foreach (DirectoryInfo dirInfo in subDirs)
                {
                    // Resursive call for each subdirectory.
                    WalkDirectoryTree(dirInfo);
                }
              } 

            }
            filex.Close();// Because at end filestream needs to close
        }

but get an error about cannot convert lamba expression to type bool because it is not a delegate

Let me know if you want to see the other code, and I will then add it, just seems a bit much.

d is not a string here, it's a DirectoryInfo . Change your isExcluded method signature to deal with the type of d properly.

Your signature is:

static bool isExcluded(List<string> exludedDirList, string target)

It should be:

static bool isExcluded(List<string> exludedDirList, DirectoryInfo target)

And your method will end up being:

//method to check
static bool isExcluded(List<string> exludedDirList, DirectoryInfo target)
{
    return exludedDirList.Any(d => target.Name.Equals(d));
}

The problem is here:

foreach (DirectoryInfo subds in subDirs.Where(d => !isExcluded(_excludedDirectories, d)))

subDirs is of type DirectoryInfo, your isExcluded takes a string as the second argument.

You want:

foreach (DirectoryInfo subds in subDirs.Where(d => !isExcluded(_excludedDirectories, d.Name)))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM