2012-01-11 9 views
11

मुझे उम्मीद है कि मैं एक काम करने में सक्षम हूं लेकिन मैं समझ नहीं पा रहा हूं कि यह कोड सही तरीके से क्यों काम नहीं कर रहा है और सूची में डुप्लिकेट प्रविष्टियों को जोड़ने की अनुमति क्यों दे रहा है।डुप्लिकेट सूची को रोकना <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 { } 
    } 
} 

मैंने सोचा कि मैं जिसमें प्राप्त करने के लिए एक और तरीका मिल गया था इस का उपयोग करते हुए "अलग"

हालांकि, ऐसा लगता 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

'फाइलइन्फो की वहीता क्या है, शायद आपको' विशिष्ट ' – Jodrell

+0

को पास करने के लिए 'IEqualityComparer ' लागू करना चाहिए, बस एक नोट: यदि 'युक्त' रिटर्न _true_ है, तो क्यों हटाएं और जोड़ें? नकारात्मक जांच करें और केवल तभी जोड़ें जब सूची में मूल्य नहीं है। – Oded

+0

ओडेड: अच्छा बिंदु, यह थोड़ी सी बर्बाद कार्रवाई है। – negligible

उत्तर

18

List<T> वास्तव में डुप्लिकेट की अनुमति देता है।

FileInfo के मामले में, Contains विधि की जाँच की जाएगी कि क्या संदर्भ में एक ही हैं, लेकिन जैसा कि आप एक पूरी तरह से नईFileInfo के सेट फ़ेच कर रहे हैं, संदर्भ अलग हैं।

आपको Contains के अधिभार का उपयोग करने की आवश्यकता है जो IEqualityComparer लेता है - here देखें।

आप इसके बजाय HashSet<T> का भी उपयोग कर सकते हैं - यह एक डेटा संरचना है जो डुप्लिकेट की अनुमति नहीं देती है (हालांकि विभिन्न संदर्भों के साथ, आपको अभी भी यह समस्या होगी)।

+0

इस मामले में जो सही मदद नहीं करेगा? (FileInfo संदर्भ से तुलना की जाती है, मूल्य नहीं)। –

+3

'हैशसेट ' अच्छा है, क्योंकि तत्व पहले से मौजूद है तो यह अपवाद नहीं फेंकता है ... जैसे! –

+1

@ जेफफोस्टर मैं शर्मिंदा हूं कि आप एक रैपर का उपयोग कर सकते हैं, इस रैपर को 'आईक्वाटेबल ' के साथ बढ़ाएं, 'ईक्वल्स 'और' गेटशैशकोड 'और' हैशसेट 'को ओवरराइड करें –

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

लंबे समय से मैंने देखा है कि अगर (dragDropFiles.Any (f => f.Name == फ़ाइल) == झूठी) ' ... :) 'अगर (! dragDropFiles.Any (f => f.Name == फ़ाइल)) ' –

+0

@ एंड्रियास: इस तरह हमने पुराने दिनों में ऐसा किया था। : - बस मजाक कर रहा हूँ। असल में मैंने केवल यह जोर दिया कि मैंने ओपी के तर्क को उलटा कर दिया है (सूची में जोड़ना अब सशर्त के अंदर किया गया है)। – Groo

+0

:) अच्छी तरह से ... एक '!' आसानी से याद किया जा सकता है –

0

आप एक ही फ़ाइल के लिए आसानी से एकाधिक फ़ाइलइन्फो उदाहरण बना सकते हैं - इसलिए आपकी सूची में केवल एक बार प्रत्येक FileInfo होगा, लेकिन इसमें smae फ़ाइल के लिए एकाधिक FileInfos हो सकते हैं।

तो आपकी सबसे अच्छी शर्त हैशटेबल का उपयोग करना और FileInfo.FullName का मानदंड के रूप में उपयोग करना हो सकता है।

0

आप ICollection<T> का कार्यान्वयन और डुप्लिकेट की अनुमति नहीं है, जबकि अभी भी एक आदेश को बनाए रखना चाहते हैं, List<T> बजाय SortedSet<T> उपयोग करने पर विचार।

संबंधित मुद्दे