Предотвращение дублирования списка <T> Записи
Я ожидаю, что смогу сделать работу, но я не могу понять, почему этот код работает неправильно и позволяет добавлять дубликаты в список.
Условие оператора 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
и 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 { }
}
Ответы
Ответ 1
List<T>
действительно разрешает дубликаты.
В случае FileInfo
метод Contains
будет проверять, являются ли ссылки одинаковыми, но по мере того, как вы извлекаете полностью новый набор FileInfo
, ссылки различаются.
Вам нужно использовать перегрузку Contains
, которая принимает IEqualityComparer
- см. здесь.
Вы также можете использовать HashSet<T>
- это структура данных, которая не позволяет дублировать (хотя с разными ссылками вы все равно есть эта проблема).
Ответ 2
Поскольку реализация по умолчанию Object.Equals
сравнивает объекты по ссылке, а не по значению. Каждый экземпляр FileInfo
, который вы создаете, представляет собой другой объект, что касается .NET.
Вы можете использовать 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;
}
Ответ 3
Вы можете легко создать несколько экземпляров FileInfo для одного и того же файла - поэтому ваш список будет содержать каждую FileInfo только один раз, но он может содержать несколько файлов FileInfos для файла smae.
Таким образом, лучшим вариантом может быть использование Hashtable и использование параметра FileInfo.FullName в качестве критерия.
Ответ 4
Если вы хотите, чтобы реализация ICollection<T>
, которая не позволяет дублировать, сохраняя при этом порядок, рассмотрите SortedSet<T>
, а не List<T>
.