2012-01-11 8 views
11

私は回避することができますが、私の人生はなぜこのコードが正しく機能していないのか理解できず、重複するエントリをリストに追加することができません。重複するリストを防止する<T>のエントリ

if同一のファイルを同じ場所からドラッグしても、文の条件は決して満たされません。私はなぜ、 "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 'を' Distinct'に渡すべきです。 – Jodrell

+0

'Contains'が_true_を返すなら、なぜ削除して追加しますか?否定的なチェックを行い、リストに値が含まれていない場合のみ追加します。 – Oded

+0

Oded:良い点、それはちょっと無駄な行動です。 – negligible

答えて

18

List<T>実際に重複が許されます。 FileInfoの場合

Contains方法は、参照が同じであるかどうかをチェックされますが、FileInfoの完全新しいセットをフェッチしているとして、参照が異なっています。

Containsのオーバーロードには、IEqualityComparerhere参照)が必要です。

代わりにHashSet<T>を使用することもできます。これは重複を許可しないデータ構造です(ただし、異なる参照でもこの問題は発生します)。

+0

この場合、それはうまくいかないでしょうか? (FileInfoは値ではなく参照によって比較されます)。 –

+3

'HashSet 'は素敵です。要素がすでに存在していれば例外をスローしません...そのように! –

+1

@JeffFoster私はあなたがラッパーを使用でき、 'IEquatable 'でこのラッパーを拡張し、 '.Equals'と' .GetHashCode'をオーバーライドし、 'HashSet 'が –

6

デフォルトの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; 
} 
+0

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

+0

@アンドレアス:これは私たちが昔にやったやり方です。ちょうど冗談。実際には私はOPのロジックを逆転したことを強調するためにのみ行った(リストへの追加は今や条件付きで行われる)。 – Groo

+0

:)まあ...! '!'は簡単に見逃されるかもしれない –

0

同じファイルに対して複数のFileInfoインスタンスを簡単に作成することができます。リストにはすべてのFileInfoが一度だけ含まれますが、smaeファイル用に複数のFileInfoが存在する場合があります。

ハッシュテーブルを使用し、FileInfo.FullNameを基準として使用することをお勧めします。

0

ICollection<T>の実装で、重複を許可しないで注文を保持したい場合は、List<T>ではなくSortedSet<T>を使用することを検討してください。

関連する問題