Как методы расширения C # Linq выполняют сравнение на равенство? - PullRequest
3 голосов
/ 26 февраля 2010

Таким образом, следующее лямбда-выражение не возвращает никаких элементов в коллекции, хотя во время пошагового выполнения мне удалось проверить, что 1 элемент соответствует критериям. Я добавил образец класса с его реализацией IEquatable.

...within a method, foo is a method parameter
var singleFoo = _barCollection.SingleOrDefault(b => b.Foo == foo);

Выше ничего не возвращается. Любые предложения относительно того, что нужно сделать, чтобы выражение выше работало?

public class Foo: IEquatable<Foo> 
{
    public string KeyProperty {get;set;}
    public bool Equals(Foo other)
    {
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        return other.KeyProperty==KeyProperty;
    }
    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (ReferenceEquals(this, obj)) return true;
        if (obj.GetType() != typeof (Foo)) return false;
        return Equals((Foo) obj);
    }
    public override int GetHashCode()
    {
        return (KeyProperty != null ? KeyProperty.GetHashCode() : 0);
    }
}

Чтобы убедиться, что я не сошел с ума, я создал следующий тест nUnit, который проходит:

    [Test]
    public void verify_foo_comparison_works()
    {
        var keyString = "keyValue";
        var bar = new Bar();
        bar.Foo = new Foo { KeyProperty = keyString };
        var basicFoo = new Foo { KeyProperty = keyString };
        var fromCollectionFoo = Bars.SingleFooWithKeyValue;
        Assert.AreEqual(bar.Foo,basicFoo);
        Assert.AreEqual(bar.Foo, fromCollectionFoo);
        Assert.AreEqual(basicFoo, fromCollectionFoo);
    }

Попытка переопределения == и! =:

    public static bool operator ==(Foo x, Foo y)
    {
        if (ReferenceEquals(x, y))
            return true;
        if ((object)x == null || (object)y == null)
            return false;
        return x.KeyProperty == y.KeyProperty;
    }
    public static bool operator !=(Foo x, Foo y)
    {
        return !(x == y);
    }

Ответы [ 4 ]

5 голосов
/ 26 февраля 2010

Они используют EqualityComparer<T>.Default для сравнений на равенство и Comparer<T>.Default для упорядоченных сравнений.

MSDN - EqualityComparer<T>.Default Примечания:

Свойство Default проверяет, реализует ли тип T универсальный интерфейс System.IEquatable(Of T) и, если да, возвращает EqualityComparer(Of T), использующий эту реализацию.В противном случае он возвращает EqualityComparer(Of T), который использует переопределения Object.Equals и Object.GetHashCode, предоставленные T.

MSDN - Comparer<T>.Default Примечания:

Comparer(Of T), возвращенноеэто свойство использует общий интерфейс System.IComparable(Of T) (IComparable<T> в C #, IComparable(Of T) в Visual Basic) для сравнения двух объектов.Если тип T не реализует универсальный интерфейс System.IComparable(Of T), это свойство возвращает Comparer(Of T), использующий интерфейс System.IComparable.

4 голосов
/ 26 февраля 2010

Вы не переопределяете оператор ==.

Изменить на:

var singleFoo = _barCollection.SingleOrDefault(b => b.Foo.Equals(foo));
0 голосов
/ 13 июля 2010

Я столкнулся с аналогичной проблемой с классом IdentityKey (который имеет неявные преобразования Guid) - в этом случае нереально включить == operator переопределение.

Я говорю, что это неосуществимо, потому что при «смешанных» сравнениях мне теперь придется приводить типы, чтобы избежать неоднозначности для перегрузок оператора ==. т.е. Вместо if(guidValue = identityKeyValue) оно должно стать if((IdentityKey)guidValue == identityKeyValue)

Хотя использование .Equals является решением, оно не кажется мне естественным?

0 голосов
/ 26 февраля 2010

Вам также необходимо переопределить оператор == .

...