collection.Contains (T) метод - PullRequest
       105

collection.Contains (T) метод

2 голосов
/ 29 января 2011

Я использую System.Collections.Generic, который содержит экземпляры класса, который я написал.

Я прочитал, что метод коллекций .Contains использует object.Equals(), или реализацию метода Equals()из интерфейса IEquatable.

Я переопределил метод объекта, а также реализовал из интерфейса.Однако Queue.Contains(instance) всегда возвращает false.Что я делаю не так?

Например ...

class Foo : IEquatable<Foo>
{
    ...
    int fooField1;
    ...

    public override bool Equals(object obj)
    {
         Foo other = obj as Foo;
         bool isEqual = false;

         if (other.fooField1 == this.fooField1)
         { 
             isEqual = true;
         }

         return isEqual;         
    }

    public bool Equals(Foo other)
    {
         bool isEqual = false;

         if (other.fooField1 == this.fooField1)
         { 
             isEqual = true;
         }

         return isEqual;         
    }

}
...

void SomeFunction()
{
    Queue<Foo> Q = new Queue<Foo>();
    Foo fooInstance1 = new Foo();
    Foo fooInstance2 = new Foo();

    fooInstance1.fooField1 = 5;
    fooInstance2.fooField1 = 5;

    Q.Enqueue(fooInstanec1);
    if(Q.Contains(fooInstance2) == false)
    {
         Q.Enqueue(fooInstance2);
    }
}

fooInstance2 всегда добавляется в очередь.Фактически, когда я запускаю это на отладчике, реализации Equals никогда не достигаются.

Что я делаю не так?

Ответы [ 4 ]

6 голосов
/ 29 января 2011

Ваш пример кода работает, как и ожидалось, как только исходные ошибки компиляции будут улажены. Не то чтобы это относилось к поставленной проблеме, прочитайте о переопределении Equals (вам также нужно переопределить GetHashCode и проверить наличие ошибок, таких как null / type-mismatch).

class Foo : IEquatable<Foo>
    {
        private int _fooField1;
        public Foo(int value)
        {
            _fooField1 = value;
        }

        public override bool Equals(object obj)
        {
            return Equals(obj as Foo);
        }

        public bool Equals(Foo other)
        {
            return (other._fooField1 == this._fooField1);
        }
    }



    class Program
    {
        static void SomeFunction()
        {
            var Q = new Queue<Foo>();
            Foo fooInstance1 = new Foo(5);
            Foo fooInstance2 = new Foo(5);

            Q.Enqueue(fooInstance1);
            if (!Q.Contains(fooInstance2))
            {
                Q.Enqueue(fooInstance2);
            }
            else
            {
                Console.Out.WriteLine("Q already contains an equivalent instance ");
            }
        }

        static void Main(string[] args)
        {
            SomeFunction();
        }
    }
1 голос
/ 29 января 2011

Вам необходимо также переопределить метод GetHashCode () в вашем классе Foo.

0 голосов
0 голосов
/ 29 января 2011
fooInstance1.fooField1 = 5;
fooInstance1.fooField2 = 5;

Вы дважды обновили fooInstance1.Вторая строка должна сказать fooInstance2.fooField1 = 5;.

Как только это исправлено, Q.Contains возвращает True, как и ожидалось.


Кроме этого, вам необязательно реализовывать IEquatable.Каждый объект имеет переопределяемый метод Equals.Вы можете просто перезаписать это.Будьте осторожны, когда реализуете свой собственный метод сравнения.Ваша реализация, показанная в этом примере, очень открыта для исключений NullReference.Примерно так будет лучше:
public override bool Equals(object obj)
{
    if(obj == null)
        return false;

    Foo other = obj as Foo;
    if(other == null)
        return false;

    return fooField1 == other.fooField1;
}

Как уже упоминали другие, если вы идете по этому маршруту и ​​переопределяете Equals, вы должны переопределить и GetHashCode.Есть несколько других вещей, которые вы должны рассмотреть.Подробнее см. на этой странице MSDN .

...