11
votes

Prévenir la liste dupliquaté Entrées

Je m'attends à ce que je puisse faire un travail autour, mais je ne peux pas comprendre pourquoi ce code ne fonctionne pas correctement et permettant d'ajouter des entrées en double à être ajoutées à la liste.

Le Si la condition de l'instruction code> n'est jamais remplie, même lorsque je fais glisser des fichiers identiques à partir du même emplacement. Je ne comprends pas pourquoi la méthode "contient" ne les correspond pas. P>

P>

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


3 commentaires

Qu'est-ce qui fait fileinfo s idérable, vous devez peut-être implémenter un iéqualitycomparer pour passer à distinct


Juste une note: si contient renvoie true , pourquoi supprimer et ajouter? Faites une vérification négative et seulement ajouter si la liste ne pas contient la valeur.


Oded: Bon point, c'est un peu une action gaspillée.


4 Réponses :


18
votes

liste permet en effet des doublons.

dans le cas de fileinfo , la méthode contient vérifiera si les références sont identiques, mais lorsque vous récupérez un tout neuf Ensemble de fichierInfo , les références sont différentes.

Vous devez utiliser la surcharge de contient qui prend un iéqualitycomparer - voir ICI .

Vous pouvez également utiliser hashset < / a> à la place - il s'agit d'une structure de données qui ne permet pas des doublons (bien que des références différentes, vous aurez toujours ce problème).


8 commentaires

Dans ce cas, cela ne vous aiderait pas correctement? (FileInfo est comparé par référence, pas de valeur).


hashset est bien, car il ne jette pas une exception si l'élément est déjà présent ... comme ça!


@JEFFEFTOSTER Je suis shur que vous puissiez utiliser un wrapper, améliorer ce wrapper avec iéquatif , remplacement anse et .gethashcode et < code> hashset devrait fonctionner


@Jefffoster - tout à fait juste. Mise à jour déjà ma réponse à cet effet.


Pour la question de la performance, je n'utiliserais pas list . Pourquoi? Dans chaque itération, vous faites un .Contains ou . Nan (qui manque de comparaison basée sur hachage) - "meilleur" cas: chaque itération ajoute un article ... pourquoi pas Créer un Dictionnaire , dans lequel la clé est une représentation (invariante et ignorée) de la propriété EG FULLNAME . Cela vous donnera un boost de performance, comme .Containskey fera une vérification basée sur HASH (tandis que la liste -Solution manque ce genre de contrôle). Ensuite, vous utilisez simplement le .values ​​ -Property ...


Merci, je pense que cette méthode peut être bénéfique pour moi plus tard, car j'aurai besoin d'une référence unique pour permettre à l'utilisateur de supprimer des outils de Toolstripmenuitem spécifiques qui seront générés sur la base de la liste.


@Andreasniedermair Il n'est pas nécessaire d'utiliser une enveloppe; Vous pouvez fournir votre propre implémentation de IequalityComparer qui teste basé sur le chemin complet.


@Phoog Ah, n'a pas pensé à l'autre Ctor ... merci! Quoi qu'il en soit, je n'utiliserais pas hashset nom pour cela ...



6
votes

Parce que la mise en œuvre par défaut objet.equals CODE> compare les objets par référence, pas par la valeur. Chaque instance fileInfo code> que vous créez est un objet différent, en ce qui concerne .NET est concerné.

Vous pouvez utiliser LINQ pour spécifier votre prédicat de comparaison personnalisé afin de comparer des objets par différentes propriétés: P >

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


10 commentaires

Long Time depuis que j'ai vu si (dragdropfiles.ca (f => f.name == fichier) == false) ... :) if (! dragdropfiles.ca (f = > F.Name == Fichier))


@Andreas: C'est la façon dont nous l'avons fait dans les vieux jours. :-D juste rigoler. En fait, je ne l'ai fait que souligner que j'ai inversé la logique d'OP (ajout à la liste est maintenant fait à l'intérieur du conditionnel).


:) eh bien ... un ! pourrait facilement être manqué


Attention: cela pourrait fonctionner pour ce cas particulier - mais dans d'autres secenarios, je préférerais aller pour une comparaison invariante et d'ignorer. Cela peut être facilement fait en passant system.stringcomparer.currentcultureignorecase ou system.stringcomparer.invariantcultureignorecase dans .distinct


@Andreasniedermairir: Afaik, deux noms de fichiers ne peuvent pas rester dans un même dossier et ne diffèrent que par le boîtier, mais s'il y a un potentiel que les noms de fichiers pouvaient obtenir un boîtier différent, je suis d'accord, ce serait plus sûr.


Je crois que vous pouvez le faire sur * Nix Systems - pas sûr de cependant (comme je ne suis pas un gars de pingouin ...) ... en plus de cela: c'est pourquoi j'ai dit "mais dans d'autres scénarios"


Merci pour la réponse mais pourriez-vous expliquer où vient la variable "F"? Comment est-il déclaré comme le bon type?


EDIT: OK, donc sur les tests, j'ai découvert que cette solution ne fonctionne pas. Bien qu'il n'ayant pas affiche les éléments en double lorsque je dépose la liste dans une liste de liste, elle ajoute toujours l'entrée en double à ma liste. J'ai pris une capture d'écran pour démontrer ceci: i42.tinypic.com/5znrd.png programme en cours d'exécution: i42.tinypic.com/xc7rpi.png


@negligible: effacez-vous la liste avant d'ajouter des éléments ( dragdropfiles.clear () ), si vous répétez cette action? Je ne vois pas comment il pourrait ajouter des doublons s'il est initialement vide. Il pourrait y avoir une possibilité d'avoir des boîtiers différents, mais ils semblent égaux en fonction de votre capture d'écran. Si vous ne voulez pas l'effacer, au lieu de addrange , changez simplement la liste entière (j'ai mises à jour ma réponse) .


@Groo: Cela générera de manière dynamique un élément de menu contextuel pour chaque élément de liste. Donc, si j'ai effacé les dragdropfiles à chaque fois que l'utilisateur doit les faire glisser dans l'application pour qu'ils apparaissent à nouveau sur le menu. (J'ai longtemps terminé ce projet actuel maintenant)



0
votes

Vous pouvez facilement créer plusieurs instances FileInfo pour le même fichier - votre liste contiendra chaque fichierInfo une seule fois, mais il peut avoir plusieurs fichiersInfos pour le fichier SMAE.

Donc, votre meilleur pari peut être d'utiliser une hache et d'utiliser FILEInfo.fulName comme critère.


0 commentaires

0
votes

Si vous souhaitez une implémentation de ICOLLECLE qui ne permet pas des doublons, tout en conservant une commande, envisagez d'utiliser triède plutôt que liste . .


0 commentaires