IComparer和SortedDictionary可能存在问题

时间:2012-07-11 07:00:00

标签: c# sorting dictionary icomparer

我正在尝试创建一个SortedDictionary,其中的键是一个表示文件/文件夹路径的字符串。我试图根据路径深度对该字典进行排序。我的标准只检查每个路径中的斜杠数,并在字典的开头放置斜杠最多的路径。

我的问题是,对于一些我无法检测到的奇怪问题,字典可以有多个完全相同的键。经过数小时调试的问题似乎是“有时”我的IComparer实现在调用ContainsKey方法或添加新值时不会遍历字典中的所有条目到字典。我没有例外或任何事情。

这是我的代码......(有点长):

 namespace ConsoleApplication1
{

    class DepthComparer : IComparer<string>
    {
        public int Compare(string X, string Y)
        {
            //Sort From deepest to shallowest 
            //C:\Users\NAME\Desktop\Folder\ should precede C:\Users\NAME\Desktop\
            //Paths with same root level are ignored

            int nXSlashes = SlashCounter(X);
            int nYSlashes = SlashCounter(Y);

            if (string.Compare(X, Y, true) == 0) //same path
            {
                return 0;
            }

            //Put Deepest Path at the beginning
            return (nXSlashes > nYSlashes ? -1 : 1);

        }

        public int SlashCounter(string stPath)
        {
            int nSlashes = 0;
            for (int i = 0; i < stPath.Length - 1; ++i)
            {
                if (stPath[i] == ('/') || stPath[i] == ('\\'))
                    nSlashes++;
            }
            return nSlashes;
        }
    }

    public class ScanOptions
    {
        public enum ExcludeRule
        {
            Invalid = 0x00,
            File = 0x01,
            Folder = 0x02,
            FileFolder = File | Folder,
        }

        private SortedDictionary<string, ExcludeRule> _dExcludedPaths;

        public ScanOptions()
        {
            _dExcludedPaths = null;            
        }

        //Creates a new Excluded Paths List (Automatically clears the current list if its already initialized)
        public void CreateExcludedPathsList()
        {
            if (_dExcludedPaths == null)
                _dExcludedPaths = new SortedDictionary<string, ExcludeRule>(new DepthComparer());
            else
                ClearExcludedPathsList();
        }

        public void ClearExcludedPathsList()
        {
            _dExcludedPaths.Clear();
        }

        public bool IsExcludedPathsListInitialized()
        {
            return _dExcludedPaths != null ? true : false;
        }

        public void AddExcludePath(string stPath, ExcludeRule Rule)
        {
            if (!IsExcludedPathsListInitialized())
                return;

            if (string.IsNullOrEmpty(stPath) || Rule == ExcludeRule.Invalid)
                return;

            string stTmp = stPath.ToLower();
            try
            {
                if (stTmp.EndsWith("\\"))
                {
                    stTmp = stTmp.Remove(stTmp.Length - 1);
                }

                if (_dExcludedPaths.ContainsKey(stTmp))
                {
                    ExcludeRule OldRule = ExcludeRule.Invalid;
                    if (_dExcludedPaths.TryGetValue(stTmp, out OldRule))
                    {
                        if ((OldRule & Rule) == 0)
                            _dExcludedPaths[stTmp] |= Rule; //Same path new rule, append rule to existing one
                    }
                    return;
                }
                else
                {
                    //brand new entry
                    _dExcludedPaths[stTmp] = Rule;
                }
            }
            catch
            {

            }
        }

        public void AddExcludePaths(List<string> ExcludePaths, ExcludeRule Rule)
        {
            if (!IsExcludedPathsListInitialized())
                return;

            foreach (string stPath in ExcludePaths)
                AddExcludePath(stPath, Rule);
        }

        public void AddExcludePaths(SortedDictionary<string, ExcludeRule> ExcludePaths)
        {
            if (!IsExcludedPathsListInitialized())
                return;

            foreach (KeyValuePair<string, ExcludeRule> PathRule in ExcludePaths)
                AddExcludePath(PathRule.Key, PathRule.Value);
        }


        public void ShowInConsole()
        {
           foreach (KeyValuePair<string, ScanOptions.ExcludeRule> Rule in _dExcludedPaths)
            {
                Console.WriteLine(Rule.Key + "\t" + Rule.Value);
            }
        }

    }

    class Program
    {
        static void Main(string[] args)
        {

            string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);

            //Fill a new string list with some paths
            List<string> ExcludedPaths = new List<string>();
            string ExPath = desktopPath + "\\12345678\\";
            ExcludedPaths.Add(ExPath);
            ExPath = desktopPath + "\\abcdefg\\";
            ExcludedPaths.Add(ExPath);
            ExPath = desktopPath + "\\ABCDEFG\\";
            ExcludedPaths.Add(ExPath);
            ExPath = desktopPath + "\\1A2B3C 4D5E6F\\123456\\4567896\\";
            ExcludedPaths.Add(ExPath);
            ExPath = desktopPath + "\\CDEVQWER ASD\\456786\\";
            ExcludedPaths.Add(ExPath);

            //Create the exclude list object
            ScanOptions scanOpt = new ScanOptions();
            scanOpt.CreateExcludedPathsList();

            //First manually add one of the paths from the list above
            scanOpt.AddExcludePath(desktopPath + "\\12345678\\", ScanOptions.ExcludeRule.Folder);

            //Now add the whole list of paths to the exclude list in scan options
            scanOpt.AddExcludePaths(ExcludedPaths, ScanOptions.ExcludeRule.Folder);

            //Now add the first entry a couple more times with different value each time
            scanOpt.AddExcludePath(desktopPath + "\\12345678\\", ScanOptions.ExcludeRule.File);

            scanOpt.AddExcludePath(desktopPath + "\\12345678\\", ScanOptions.ExcludeRule.Folder);


            //Dump the list to console
            //We now have two keys in the dictionary that equal desktopPath + "\\12345678\\"
            scanOpt.ShowInConsole();

        }
    }
}

在Main()_dExcludedPaths的末尾,它的两个键完全相同。

有人可以帮助理解这里发生的事情以及如何在字典中复制密钥?

由于

1 个答案:

答案 0 :(得分:1)

    public int Compare(string X, string Y) 
    {  
        int nXSlashes = SlashCounter(X); 
        int nYSlashes = SlashCounter(Y); 

        if (nXSlashes > nYSlashes)
          return -1;
        if (nXSlashes < nYSlashes)
          return 1;

        return string.Compare(X, Y, true);          
    }