C# 防止重复的 List<T> 条目

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8819058/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 04:37:26  来源:igfitidea点击:

Preventing Duplicate List<T> Entries

c#listcollectionsduplicates

提问by negligible

I expect I'll be able to make a work around but I can't for the life of me understand why this code is not functioning correctly and allowing duplicate entries to be added to the List.

我希望我能够解决问题,但我终其一生都无法理解为什么此代码无法正常运行并允许将重复条目添加到列表中。

The ifstatement condition is never met, even when I drag identical files in from the same location. I don't understand why the "Contains" method isn't matching them up.

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 { }
    }
}

I thought I had found another method in which to achieve this using "Distinct"

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

However, it appears checkedDragDropFiles& dragDropFileshave the same amount of entries, including duplicates, except when dragDropFilesis displayed in a ListBoxit doesn't show them. Why does it do this?

但是,它出现checkedDragDropFilesdragDropFiles具有相同数量的条目,包括重复项,除非dragDropFiles在 a 中显示时ListBox不显示它们。它为什么这样做?

I need to prevent any duplicated list entries, as I would be programmatically creating a menu based off of the list data.

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

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 { }
}

采纳答案by Oded

List<T>does indeed allow duplicates.

List<T>确实允许重复。

In the case of FileInfo, the Containsmethod will be checking whether the references are the same, but as you are fetching a completely newset of FileInfo, the references are different.

在 的情况下FileInfo,该Contains方法将检查引用是否相同,但是当您获取一组全新的 时FileInfo,引用是不同的。

You need to use the overload of Containsthat takes an IEqualityComparer- see here.

您需要使用重载的Contains接受一个IEqualityComparer-看这里

You can also use HashSet<T>instead - it is a data structure that does not allow duplicates (though with different references, you will still have this issue).

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

回答by Groo

Because the default Object.Equalsimplementation compares objects by reference, not by value. Each FileInfoinstance you create is a different object, as far as .NET is concerned.

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

You can use LINQ to specify your custom comparison predicate in order to compare objects by different property:

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

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

[Edit]

[编辑]

Since strings are compared by value, you might as well filter the list beforeyou project it to FileInfo, like this:

由于字符串是按值比较的,您不妨将其投影到之前过滤列表FileInfo,如下所示:

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

回答by Eugen Rieck

You can easily create multiple FileInfo instances for the same file - so your list will contain every FileInfo only once, but it may have multiple FileInfos for the smae file.

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

So your best bet might be to use a Hashtable and use FileInfo.FullName as criterion.

因此,您最好的选择可能是使用 Hashtable 并使用 FileInfo.FullName 作为标准。

回答by Ian Nelson

If you want an implementation of ICollection<T>that does not allow duplicates, whilst still retaining an ordering, consider using SortedSet<T>rather than List<T>.

如果您想要一个ICollection<T>不允许重复的实现,同时仍然保留排序,请考虑使用SortedSet<T>而不是List<T>.