web-dev-qa-db-fra.com

Qu'est-ce que Collection.Contains () utilise pour vérifier les objets existants?

J'ai une liste fortement typée d'objets personnalisés, MyObject, qui a un ID de propriété ainsi que d'autres propriétés.
Disons que l'ID d'un MyObject le définit comme unique et je veux vérifier si ma collection n'a pas déjà un objet MyObject qui a un ID de 1 avant d'ajouter mon nouveau MyObject à la collection.
Je veux utiliser if (! List.Contains (myObj)) mais comment puis-je appliquer le fait que seulement une ou deux propriétés de MyObject le définissent comme unique?
Puis-je utiliser IComparable? Ou dois-je seulement remplacer une méthode Equals mais j'aurais besoin d'hériter d'abord de quelque chose, n'est-ce pas?



Merci

47
topwik

List<T>.Contains Utilise EqualityComparer<T>.Default, Qui à son tour utilise IEquatable<T> Si le type l'implémente, ou object.Equals Sinon.

Vous pouvez simplement implémenter IEquatable<T> Mais c'est une bonne idée de remplacer object.Equals Si vous le faites, et une très bonne idée de remplacer GetHashCode() si vous faites cela:

public class SomeIDdClass : IEquatable<SomeIDdClass>
{
    private readonly int _id;
    public SomeIDdClass(int id)
    {
        _id = id;
    }
    public int Id
    {
        get { return _id; }
    }
    public bool Equals(SomeIDdClass other)
    {
        return null != other && _id == other._id;
    }
    public override bool Equals(object obj)
    {
        return Equals(obj as SomeIDdClass);
    }
    public override int GetHashCode()
    {
        return _id;
    }
}

Notez que le code de hachage se rapporte aux critères d'égalité. C'est vital.

Cela le rend également applicable à tout autre cas où l'égalité, telle que définie en ayant le même ID, est utile. Si vous avez une exigence unique pour vérifier si une liste contient un tel objet, alors je suggérerais probablement de faire simplement:

return someList.Any(item => item.Id == cmpItem.Id);
48
Jon Hanna

List<T> utilise le comparateur renvoyé par EqualityComparer<T>.Default et selon la documentation pour cela:

La propriété Default vérifie si le type T implémente l'interface System.IEquatable (Of T) et, dans l'affirmative, renvoie un EqualityComparer (Of T) qui utilise cette implémentation. Sinon, il renvoie un EqualityComparer (Of T) qui utilise les remplacements d'Object.Equals et Object.GetHashCode fournis par T.

Vous pouvez donc soit implémenter IEquatable<T> sur votre classe personnalisée, ou remplacez les méthodes Equals (et GetHashCode) pour effectuer la comparaison par les propriétés dont vous avez besoin. Vous pouvez également utiliser linq:

bool contains = list.Any(i => i.Id == obj.Id);
28
Lee

Vous pouvez utiliser LINQ pour le faire assez facilement.

var result = MyCollection.Any(p=>p.myId == Id);
if(result)
{
     //something
}
6
Robaticus

Vous pouvez remplacer Equals et GetHashCode, implémenter un IEqualityComparer<MyObject> et utilisez-le dans l'appel Contains, ou utilisez une méthode d'extension comme Any

if (!myList.Any(obj => obj.Property == obj2.Property && obj.Property2 == obj2.Property2))
   myList.Add(obj2);
2
Anthony Pegram

Vous pouvez utiliser IEquatable<T>. Implémentez cela dans votre classe, puis vérifiez si le T transmis à Equals a le même identifiant que this.Id. Je suis sûr que cela fonctionne pour vérifier une clé dans un dictionnaire, mais je ne l'ai pas utilisé pour une collection.

0
davisoa

Définissez d'abord la classe d'assistance avec IEqualityComparer.

public class MyEqualityComparer<T> : IEqualityComparer<T>
{
    Func<T, int> _hashDelegate;

    public MyEqualityComparer(Func<T, int> hashDelegate)
    {
        _hashDelegate = hashDelegate;
    }

    public bool Equals(T x, T y)
    {
        return _hashDelegate(x) == _hashDelegate(y);
    }

    public int GetHashCode(T obj)
    {
        return _hashDelegate(obj);
    }
}

Ensuite, dans votre code, définissez simplement le comparateur et utilisez-le:

var myComparer = new MyEqualityComparer<MyObject>(delegate(MyObject obj){
    return obj.ID;
});

var result = collection
   .Where(f => anotherCollection.Contains(f.First, myComparer))
   .ToArray();

De cette façon, vous pouvez définir la façon dont l'égalité est calculée sans modifier vos classes. Vous pouvez également l'utiliser pour traiter des objets provenant de bibliothèques tierces car vous ne pouvez pas modifier leur code.

0
Tomas Kubes