2012-01-11 7 views
11

나는이 문제를 제대로 해결하지 못하고 목록에 중복 항목을 추가 할 수없는 이유를 이해할 수 없다고 생각합니다.중복 목록 방지 <T> 항목

동일한 위치에서 동일한 파일을 드래그하더라도 문 조건은 충족되지 않습니다. "Contains"방법이 왜 일치하지 않는지 이해할 수 없습니다.

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

는 내가 달성하기에 다른 방법을 발견했다고 생각이

그러나, 제외하고, checkedDragDropFiles & dragDropFiles 중복을 포함한 항목의 동일한 금액을 표시하여 "고유" dragDropFilesListBox에 표시되면 표시되지 않습니다. 왜 이렇게합니까?

목록 데이터를 기반으로 메뉴를 프로그래밍 방식으로 작성하므로 중복 된 목록 항목을 방지해야합니다.

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

무엇이'FileInfo's를 동일하게 만들었습니까?'IEqualityComparer '을 구현하면됩니다. – Jodrell

+0

'Contains'가 _true_를 반환한다면 왜 제거하고 추가해야합니까? 음수 검사를 수행하고 목록에 값이 들어 있지 않으면 _ 추가하십시오. – Oded

+0

Oded : 좋은 지적입니다. 다소 낭비되는 행동입니다. – negligible

답변

18

List<T> 실제로 복제가 허용됩니다. 당신이 FileInfo 완전히 새로운 세트를 가져 오는대로 FileInfo의 경우

Contains 방법은 참조가 동일 여부를 확인됩니다 만, 참조는 다르다.

Contains의 과부하에는 IEqualityComparer이 필요합니다 (here 참조).

대신 HashSet<T>을 사용할 수도 있습니다. 이는 중복을 허용하지 않는 데이터 구조입니다 (다른 참조로도이 문제가 발생 함).

+0

이 경우에는 도움이되지 않을까요? (FileInfo는 값이 아닌 참조로 비교됩니다.) –

+3

'HashSet '이 멋지다. 요소가 이미 존재하면 ... 예외가 발생하지 않는다. –

+1

@JeffFoster 나는 래퍼를 사용할 수 있고, IEquatable '으로이 래퍼를 향상시키고,'.Equals','.GetHashCode' 및'HashSet '이 –

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; 
} 
+0

'if (dragDropFiles.Any (f => f.Name == file) == false)' ... :)'if (! dragDropFiles.Any (f => f.Name == file))' –

+0

@ Andreas : 이것은 우리가 옛날에했던 방식입니다. 농담이야. 실제로 저는 OP의 논리를 뒤집 었음을 강조하기 위해서만했습니다 (목록에 추가하는 것은 조건부에서 수행됩니다). – Groo

+0

:) 음 ... '!'는 쉽게 놓칠 수 있습니다. –

0

동일한 파일에 대해 여러 개의 FileInfo 인스턴스를 쉽게 만들 수 있습니다. 목록에 모든 FileInfo가 한 번만 포함되지만 smae 파일에 대해 여러 개의 FileInfos가있을 수 있습니다.

따라서 가장 좋은 방법은 Hashtable을 사용하고 FileInfo.FullName을 기준으로 사용하는 것일 수 있습니다.

0

중복을 허용하지 않는 ICollection<T>의 구현을 계속 유지하면서 주문을 유지하려는 경우 List<T> 대신 SortedSet<T>을 사용해보십시오.