Preventing Duplicate List<T> Entries

半腔热情 提交于 2019-12-23 07:09:08

问题


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 if statement 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.

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"

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

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

回答1:


List<T> does indeed allow duplicates.

In the case of FileInfo, the Contains method will be checking whether the references are the same, but as you are fetching a completely new set of FileInfo, the references are different.

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

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).




回答2:


Because the default Object.Equals implementation compares objects by reference, not by value. Each FileInfo instance you create is a different object, as far as .NET is concerned.

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

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 before you project it to FileInfo, like this:

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



回答3:


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.

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




回答4:


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>.



来源:https://stackoverflow.com/questions/8819058/preventing-duplicate-listt-entries

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!