防止重复列表<t>条目</t>

时间:2012-01-11 12:15:21

标签: c# list collections duplicates

我希望我能够解决这个问题,但是我无法理解为什么这段代码无法正常运行并允许将重复的条目添加到列表中。

即使我从同一位置拖动相同的文件,也永远不会满足if语句条件。我不明白为什么“包含”方法不匹配它们。

public class Form1:Form {
    private List<FileInfo> dragDropFiles = new List<FileInfo>();

    private void Form1_DragDrop(object sender, DragEventArgs e) {
        try {
            if (e.Data.GetDataPresent(DataFormats.FileDrop)) {
                string[] files =
                    (string[])e.Data.GetData(DataFormats.FileDrop);

                OutputDragDrop(files);
            }
        }
        catch { }
    }

    private void Form1_DragEnter(object sender, DragEventArgs e) {
        if (e.Data.GetDataPresent(DataFormats.FileDrop))
            e.Effect = DragDropEffects.Copy;
        else
            e.Effect = DragDropEffects.None;
    }

    private void OutputDragDrop(string[] files) {
        try {
            foreach (string file in files) {
                FileInfo fileInfo = new FileInfo(file);

                if (dragDropFiles.Contains(fileInfo)) {
                    dragDropFiles.Remove(fileInfo);
                }
                dragDropFiles.Add(fileInfo);
            }
            PopulateContextMenu();
        }
        catch { }
    }
}

我以为我找到了另一种使用“Distinct”实现此目的的方法

然而,它出现checkedDragDropFiles&amp; dragDropFiles具有相同数量的条目,包括重复条目,除非dragDropFiles中显示的ListBox未显示它们。为什么这样做?

我需要阻止任何重复的列表条目,因为我将以编程方式创建基于列表数据的菜单。

private void OutputDragDrop(string[] files)
{
    try
    {
        foreach (string file in files)
        {
            FileInfo fileInfo = new FileInfo(file);

            //if (dragDropFiles.Contains(fileInfo))
            //{
            //    dragDropFiles.Remove(fileInfo);
            //}
            dragDropFiles.Add(fileInfo);
        }

        List<FileInfo> checkedDragDropFiles = dragDropFiles.Distinct().ToList();

        debugList.DataSource = checkedDragDropFiles;
        debugList2.DataSource = dragDropFiles;
        //PopulateContextMenu();
    }
    catch { }
}

4 个答案:

答案 0 :(得分:18)

List<T>确实允许重复。

对于FileInfoContains方法将检查引用是否相同,但是当您获取完整的集{{1}时引用是不同的。

您需要使用FileInfo的{​​{1}}重载 - 请参阅here

您也可以使用HashSet<T> - 这是一个不允许重复的数据结构(虽然使用不同的引用,但您仍会遇到此问题)。

答案 1 :(得分:6)

因为默认的Object.Equals实现按引用比较对象,而不是按值。就.NET而言,您创建的每个FileInfo实例都是一个不同的对象。

您可以使用LINQ指定自定义比较谓词,以便按不同属性比较对象:

if (dragDropFiles.Any(f => f.Name == file) == false)
{
    dragDropFiles.Add(fileInfo);
}

<强> [编辑]

由于字符串是按值进行比较的,因此您也可以过滤列表,然后将其投影到FileInfo,如下所示:

private void OutputDragDrop(string[] files)
{
    dragDropFiles = files.Distinct().Select(f => new FileInfo(f)).ToList();
    debugList.DataSource = checkedDragDropFiles;
    debugList2.DataSource = dragDropFiles;
}

答案 2 :(得分:0)

您可以轻松地为同一个文件创建多个FileInfo实例 - 因此您的列表将仅包含每个FileInfo一次,但它可能具有多个用于smae文件的FileInfos。

所以你最好的选择可能是使用Hashtable并使用FileInfo.FullName作为标准。

答案 3 :(得分:0)

如果您希望ICollection<T>的实施不允许重复,同时仍保留排序,请考虑使用SortedSet<T>而不是List<T>