Using equality comparer in lambda expression - c#

I have a Venue class, and a Coordinate class like so:
class Venue
{
string Name;
Coordinate coordinate;
}
class Coordinate
{
double latitute;
double longitude;
}
Now, I want to be able to select a venue based on a coordinate as follows:
List<Venue> venues = GetAllVenues();
var myVenue = venues.FirstOrDefault(venue=>venue.coordinate == myCoordinate);
I have an IEqualityComparer implementation, but the lambda expression does not have an overload which takes the IEqualityComparer as a parameter.
How do I use my equality comparer in a lambda expression?
EDIT:
My equality comparer looks like this:
class CoordinatesEqualityComparer:IEqualityComparer<Coordinate>
{
public bool Equals(Coordinate x, Coordinate y)
{
return x.RowIndex == y.RowIndex && x.ColumnIndex == y.ColumnIndex;
}
public int GetHashCode(Coordinate obj)
{
return obj.GetHashCode();
}
}
When I do a Union() operation, like so, it does not work correctly, even though coordinates in both lists are same.
List<Coordinates> coordinates;
CoordinatesEqualityComparer comparer;
coordinates.Union(someOtherListOfCoordinates, comparer);
However, when I do a union with itself, it works. What am I doing wrong? Does it have something to do with the GetHashCode() implementation?
Edit 2:
Fixing the GetHashCode() method seems to do the trick.
public int GetHashCode(Coordinates obj)
{
// Warning:Hack. Use two prime numbers to generate a hash based on two properties.
return obj.RowIndex.GetHashCode() * 7 + obj.ColumnIndex.GetHashCode() * 13 ;
}

Have you tried:
var ec = new YourEqualityComparer();
var myVenue = venues.FirstOrDefault(venue =>
ec.Equals(venue.coordinate, myCoordinate));
Of course, another approach would be to define the == operator for your Coordinate class and then you wouldn't need an IEqualityComparer:
class Coordinate
{
double latitude;
double longitude;
public override bool Equals(object obj)
{
return Object.ReferenceEquals(this, obj)) ||
this == (other as Coordinate);
}
public static bool operator ==(Coordinate l, Coordinate r)
{
return ((object)l == null && (object)r == null) ||
((object)l != null && (object)r != null) &&
// equality check including epsilons, edge cases, etc.
}
public static bool operator !=(Coordinate l, Coordinate r)
{
return !(l == r);
}
}

I would implement IEquatable<Coordinate>, override Equals(object), override GetHashCode(), and == != operators like this:
public class Coordinate : IEquatable<Coordinate>
{
public double Latitide { get; set; }
public double Longitude { get; set; }
public bool Equals(Coordinate other)
{
if (other == null)
{
return false;
}
else
{
return this.Latitide == other.Latitide && this.Longitude == other.Longitude;
}
}
public override bool Equals(object obj)
{
return this.Equals(obj as Coordinate);
}
public override int GetHashCode()
{
return this.Latitide.GetHashCode() ^ this.Longitude.GetHashCode();
}
public static bool operator ==(Coordinate value1, Coordinate value2)
{
if (!Object.ReferenceEquals(value1, null) && Object.ReferenceEquals(value2, null))
{
return false;
}
else if (Object.ReferenceEquals(value1, null) && !Object.ReferenceEquals(value2, null))
{
return false;
}
else if (Object.ReferenceEquals(value1, null) && Object.ReferenceEquals(value2, null))
{
return true;
}
else
{
return value1.Latitide == value2.Latitide && value1.Longitude == value2.Longitude;
}
}
public static bool operator !=(Coordinate value1, Coordinate value2)
{
return !(value1 == value2);
}
}

Related

Create a generic method to use EqualityComparer that I have defined for specific types

I have many objects in which I want to check that lists of those objects are equal.
For each object I have defined an EqualityComparer:
public class BaseAssociatedEntity : BasePage
{
protected IWebElement EntityElement;
protected virtual IWebElement EntityLink => EntityElement.FindElement(By.TagName("a"));
public string EntityName => EntityLink.Text;
public BaseAssociatedEntity(IWebElement entityElement, IWebDriver driver, string username, string password)
: base(driver, driver.Url, username, password, TimeoutInSecondsConstants.Three)
{
EntityElement = entityElement;
}
public bool Equals(BaseAssociatedEntity that)
{
return EntityName == that.EntityName;
}
}
public class BaseAssociatedEntityEqual : EqualityComparer<BaseAssociatedEntity>
{
public override bool Equals(BaseAssociatedEntity x, BaseAssociatedEntity y)
{
if (ReferenceEquals(x, y)) return true;
if (x is null || y is null) return false;
return x.Equals(y);
}
public override int GetHashCode(BaseAssociatedEntity obj) => obj.GetHashCode();
}
I then want to call the following method to check that 2 lists of type BaseAssociatedEntity are SequenceEqual():
protected bool BothNullOrEqual(List<BaseAssociatedEntity> left, List<BaseAssociatedEntity> right)
{
if (left == null && right == null) return true;
if (left != null && right != null) return left.SequenceEqual(right, new BaseAssociatedEntityEqual());
return false;
}
But I end up writing this BothNullOrEqual method for every single object that I have:
protected bool BothNullOrEqual(List<NotificationGroupAssociatedEntity> left,
List<NotificationGroupAssociatedEntity> right)
{
if (left == null && right == null) return true;
if (left != null && right != null) return left.SequenceEqual(right, new NotificationGroupAssociatedEntityEqual());
return false;
}
And so on.. How can I make this method generic so that it works for all types, using the EqualityComparer that I have specifically defined?
Just make the method generic in both the data type and the comparer type:
public static bool BothNullOrEqual<TData, TEqualityComparer>
(IEnumerable<TData> left, IEnumerable<TData> right)
where TEqualityComparer : IEqualityComparer<TData>, new()
{
if (left is null && right is null)
{
return true;
}
if (left is null || right is null)
{
return false;
}
return left.SequenceEqual(right, new TEqualityComparer());
}
An alternative single expression version:
public static bool BothNullOrEqual<TData, TEqualityComparer>
(IEnumerable<TData> left, IEnumerable<TData> right)
where TEqualityComparer : IEqualityComparer<TData>, new() =>
left is null
? right is null
: right is object && left.SequenceEqual(right, new TEqualityComparer());

List equality of a custom class

I have a class A, which holds a string property and overwrites Equals for equality testing.
public class A
{
public string Prop { get; }
public A(string val)
{
Prop = val;
}
public override bool Equals(object obj)
{
return obj is A arg && (Prop == arg.Prop);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
I also have a class B which has a List<A> as property:
public class B
{
public IReadOnlyList<A> Prop { get; }
public B(IReadOnlyList<A> val)
{
Prop = val;
}
public override bool Equals(object obj)
{
// ...
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
I wanna be able to compare to instances of B for equality and order.
How can I write the Equals method in B by not rewriting the same code I wrote in A?
Is there a way to reuse the A Equals?
Update: My first version assumed B is derived from A.
A.Equals:
If A is not sealed, obj is A ... can return a false positive if different types are compared. So the corrected version:
public override bool Equals(object obj)
{
return obj is A other
&& this.Prop == other.Prop
&& this.GetType() == other.GetType(); // not needed if A is sealed
}
A.GetHashCode:
base.GetHashCode will return different hash codes for different but equal instances, which is wrong. Derive the hashcode from self properties instead. If Prop acts like some ID, then simply return Prop.GetHashCode()
B.Equals:
public override bool Equals(object obj)
{
return obj is B other
&& this.Prop.SequenceEqual(other.Prop) // will re-use A.Equals
&& this.Prop.GetType() == other.Prop.GetType() // not needed if different IReadOnlyList types are ok
&& this.GetType() == other.GetType(); // not needed if B is sealed
}
B.GetHashCode:
You can aggregate the hash codes of A instances. Here I use a simple XOR but if the same items can often come in a different order you can come up with something more fancy.
return Prop.Aggregate(0, (h, i) => h ^ i.GetHashCode());
Implementing Equals for a list can be done by using the SequenceEquals method (from System.Linq namespace), which ensures that each item in one list equals the item at the same index in the other list.
One thing you might consider changing, however is your implementation of GetHashCode. This method should return the same number if two items are equal (though it's not guaranteed that two items with the same hash code are equal). Using base.GetHashCode() does not meet this requirement, since the base is object in this case; according to the documentation, "hash codes for reference types are computed by calling the Object.GetHashCode method of the base class, which computes a hash code based on an object's reference", so objects only return the same HashCode if they refer to the exact same object.
The HashCode should be based on the same properties used to determine equality, so in this case we want to use Prop.GetHashCode() for class A, and we want to aggregate the hashcode for all the items in Prop for class B.
Here's one way the classes could be refactored:
public class A : IEquatable<A>
{
public string Prop { get; }
public A(string val)
{
Prop = val;
}
public bool Equals(A other)
{
if (other == null) return false;
return Prop == other.Prop;
}
public override bool Equals(object obj)
{
return Equals(obj as A);
}
public override int GetHashCode()
{
return Prop.GetHashCode();
}
}
public class B : IEquatable<B>
{
public IReadOnlyList<A> Prop { get; }
public B(IReadOnlyList<A> val)
{
Prop = val;
}
public bool Equals(B other)
{
if (other == null) return false;
if (ReferenceEquals(this, other)) return true;
if (Prop == null) return other.Prop == null;
return other.Prop != null && Prop.SequenceEqual(other.Prop);
}
public override bool Equals(object obj)
{
return Equals(obj as B);
}
public override int GetHashCode()
{
return Prop?.Aggregate(17,
(current, item) => current * 17 + item?.GetHashCode() ?? 0)
?? 0;
}
}
Linq contains a useful method to compare collections: SequenceEqual
public override bool Equals(object obj)
{
if (!(obj is B other))
{
return false;
}
if (this.Prop == null || other.Prop == null)
{
return false;
}
return this.Prop.SequenceEqual(other.Prop);
}
Also, implement IEquatable<T> when you override Equals.
How about something like this:
public override bool Equals(object obj)
{
if(!(obj is B))
{
return false;
}
var b = obj as B;
if(b.Prop.Count != this.Prop.Count)
{
return false;
}
for(var i =0; i < Prop.Count; i++)
{
if (!Prop.ElementAt(i).Equals(b.Prop.ElementAt(i)))
{
return false;
}
}
return true;
}

Compare 2 class objects and ignore 1 (or more) property?

So I created a class like this:
public class ClassName
{
public int ID;
public String n_1 {get; set; }
public String n_2 {get; set; }
// ....
public String n_x {get; set; }
}
Later in my code I compare 2 ClassName objects:
ClassName Item_1 /*...*/ ;
ClassName Item_2 /*...*/ ;
Like this:
if (Item_1 != Item_2 && Item_1.n_a == Item_2.n_a)
{
//do something
}
Now my Problem is that Item_1.ID and Item_2.ID should be ignored. Is there a easy way to do this? The only solution I came up with is a no brainer of like
if ( (Item_1.n_1 != Item_2.n_1 || Item_1.n_2 != Item_2.n_2 || /* ... */ ) && Item_1.n_a == Item_2.n_a)
Override the object.Equals method in your class and specify how you want it to be compared.
Then use !Item1.Equals(Item2) instead of !=
https://learn.microsoft.com/en-us/dotnet/api/system.object.equals?view=netframework-4.7.2
The easy way is what you are actually doing , just create a method like this
public bool Method(ClassName Item_1,ClassName Item2)
{
bool check=false;
if ( (Item_1.n_1 != Item_2.n_1 || Item_1.n_2 != Item_2.n_2 || /* ... */ ) && Item_1.n_a == Item_2.n_a)
check=true
return check
}
To perform something like Item_1 != Item_2 or Item_1 == Item_2 and get all properties (or the ones you want) to be compared, you need to implement your own Equals method and ==, != operators overloads.
== operator, from MSDN:
For reference types other than string, == returns true if its two operands refer to the same object.
For that you can start with some straightforward solution, to implement IEquatable<T> interface, fill your comparing logic inside Equals method and overload == and != operators internally calling your type-safe Equals method:
public class ClassName : IEquatable<ClassName>
{
public int ID;
public String n_1 { get; set; }
public String n_2 { get; set; }
// ....
public String n_x { get; set; }
public static bool operator ==(ClassName obj1, ClassName obj2)
{
if (((object)obj1) == null || ((object)obj2) == null)
return Equals(obj1, obj2);
return obj1.Equals(obj2);
}
public static bool operator != (ClassName obj1, ClassName obj2)
{
if (((object)obj1) == null || ((object)obj2) == null)
return !Equals(obj1, obj2);
return !obj1.Equals(obj2);
}
public bool Equals(ClassName obj)
{
if (obj == null) return false;
return (n_1 == obj.n_1) && (n_2 == obj.n_2) && (n_x == obj.n_x); //you can ignore ID here
}
public override bool Equals(object obj)
{
if (obj == null)
return false;
ClassName classNameObj = obj as ClassName;
if (classNameObj == null)
return false;
else
return Equals(classNameObj);
}
public override int GetHashCode()
{
//This code was generated by VS ide, you can write your own hashing logic
var hashCode = 1032198799;
hashCode = hashCode * -1521134295 + ID.GetHashCode();
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(n_1);
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(n_2);
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(n_x);
return hashCode;
}
}
Then you can check in your if:
if (Item_1 != Item_2)
{
//Do Something
}
For Equals method you should stick to Guidelines for Overriding Equals() and Operator == .
References: == Operator, != Operator, IEquatable Interface, IEquatable.Equals(T) Method, Guidelines for Overriding Equals() and Operator ==

Testing for value equality between two interface instances in c#?

So I have an interface, lets call it IInterface.
public interface IInterface : IEquatable<IInterface>
{
string Name { get; set; }
int Number { get; }
Task<bool> Update();
}
Then I try and implement the interface in Implementation.
public bool Equals(IInterface other)
{
if (other == null) return false;
return (this.Name.Equals(other.Name) && this.Number.Equals(other.Number));
}
public override int GetHashCode()
{
return this.Number.GetHashCode();
}
public override bool Equals(object obj)
{
var other = obj as IInterface ;
return other != null && Equals(other);
}
public static bool operator ==(Implementation left, IInterface right)
{
if (ReferenceEquals(left, right)) return true;
if (ReferenceEquals(left, null)) return false;
return left.Equals(right);
}
public static bool operator !=(Implementation left, IInterface right)
{
return !(left == right);
}
The problem I am running into is in a setter:
public IInterface MyIntf
{
get { return _myIntf; }
set
{
if (_myIntf == value) { return; }
_myIntf = value;
}
Intellisense is showing that the equality test there is testing the references only and treating both left and right as objects. I assume this is because there is no operator overload for ==(IInterface left, IInterface right). Of course, I cannot actually implement that function because == requires one of the sides to match the type of the implementing class. How does one properly make sure two interfaces can be checked for equality against each other?
Update
Got it, you cannot implement == for an interface. I will use Equals. Thanks everyone.
You should explicitly call Equals:
if (_myIntf != null && _myIntf.Equals(value)) { return; }
Implementing IEquatable<T> does not impact the == operator.
Use Equals instead of ==:
public IInterface MyIntf
{
get { return _myIntf; }
set
{
if (_myIntf.Equals(value)) { return; }
_myIntf = value;
}
}

Define how a comparison operator is applied to a type?

How can I define whether and how a comparison operator is applied to operands of my type?
You implement the IComparable interface with the CompareTo method.
To use all of the operators, try this:
public sealed class Foo : IEquatable<Foo>, IComparable<Foo>
{
public static int Compare(Foo first, Foo second)
{
if (Object.ReferenceEquals(first, null))
return (Object.ReferenceEquals(second, null) ? 0 : -1);
return first.CompareTo(second);
}
public static bool operator==(Foo first, Foo second)
{
return Object.Equals(first, second);
}
public static bool operator!=(Foo first, Foo second)
{
return !Object.Equals(first, second);
}
public static bool operator<(Foo first, Foo second)
{
return Foo.Compare(first, second) < 0;
}
public static bool operator >(Foo first, Foo second)
{
return Foo.Compare(first, second) > 0;
}
public static bool operator <=(Foo first, Foo second)
{
return Foo.Compare(first, second) <= 0;
}
public static bool operator >=(Foo first, Foo second)
{
return Foo.Compare(first, second) >= 0;
}
private string bar;
public string Bar
{
//getter and setter
}
public bool Equals(Foo other)
{
if (Object.ReferenceEquals(other, null))
return false;
if (Object.ReferenceEquals(other, this)) //Not mandatory
return true;
return String.Equals(this.foo, other.foo);
}
public int CompareTo(Foo other)
{
if (Object.ReferenceEquals(other, null))
return 1;
if (Object.ReferenceEquals(other, this)) //Not mandatory
return 0;
return String.Compare(this.bar, other.bar);
}
public override bool Equals(object obj)
{
return this.Equals(obj as Foo);
}
public override int GetHashCode()
{
return this.bar == null ? 0 : this.bar.GetHashCode();
}
}
A good tutorial on this: http://winsharp93.wordpress.com/2009/06/28/implementing-icomparablet-iequatablet-and-the-equality-members/
Since you know the interfaces IComparable, IEquatable needs to be implemented you can tell if two instances of yourClass are comparable by using this (example):
if (yourClass is IEquatable<T> && yourClass2 is IEquatable<T> && yourClass is IComparable<T> && yourClass2 is IComparable<T>) //T is the same type
{
yourClass <= yourClass2;
}
You can overload operators for your type, e.g.
public class MyComparable
{
public static bool operator <(MyComparable left, MyComparable right)
{
// other things...
}
Allows you to do this:
MyComparable c1 = // something
MyComparable c2 = // something
if (c1 < c2)
// something
(in such a case, it would probably make sense to implement IComparable<MyComparable> also.
A simple class that implements IComparable, IComparable<T>, IEquatable<T> and overrides object.Equals(object), object.GetHashCode() and the various "standard" operators ==, !=, >, <, >=, <=.
Note the use of object.ReferenceEquals(object, object) so as not to trigger StackOverflowException. This because we are overloading the == and != operators and basing them on MyClass.Equals(MyClass), so MyClass.Equals(MyClass) clearly can't use them. A common error is, in fact, inside the
bool Equals(MyClass other)
{
if (other == null)
{
}
}
Booooom! Can't do that. Because the if (other == null) will recursively call the other.Equals((MyClass)null). What you could do is: if (((object)other) == null), because in C# operators can't be virtual, so here we are using the == of the object class.
InnerEquals and InnerCompareTo are present so the null check mustn't be done twice if the Equals(object) or CompareTo(object) are called.
public class MyClass : IComparable<MyClass>, IComparable, IEquatable<MyClass>
{
public int MyInt1 { get; set; }
public int MyInt2 { get; set; }
public int CompareTo(MyClass other)
{
if (object.ReferenceEquals(other, null))
{
return 1;
}
return this.InnerCompareTo(other);
}
int IComparable.CompareTo(object obj)
{
// obj is object, so we can use its == operator
if (obj == null)
{
return 1;
}
MyClass other = obj as MyClass;
if (object.ReferenceEquals(other, null))
{
throw new ArgumentException("obj");
}
return this.InnerCompareTo(other);
}
private int InnerCompareTo(MyClass other)
{
// Here we know that other != null;
if (object.ReferenceEquals(this, other))
{
return 0;
}
int cmp = this.MyInt1.CompareTo(other.MyInt1);
if (cmp == 0)
{
cmp = this.MyInt2.CompareTo(other.MyInt2);
}
return cmp;
}
public override bool Equals(object obj)
{
// obj is object, so we can use its == operator
if (obj == null)
{
return false;
}
MyClass other = obj as MyClass;
if (object.ReferenceEquals(other, null))
{
return false;
}
return this.InnerEquals(other);
}
public bool Equals(MyClass other)
{
if (object.ReferenceEquals(other, null))
{
return false;
}
return this.InnerEquals(other);
}
private bool InnerEquals(MyClass other)
{
// Here we know that other != null;
if (object.ReferenceEquals(this, other))
{
return true;
}
return this.MyInt1 == other.MyInt1 && this.MyInt2 == other.MyInt2;
}
public override int GetHashCode()
{
unchecked
{
// From http://stackoverflow.com/a/263416/613130
int hash = 17;
hash = hash * 23 + this.MyInt1;
hash = hash * 23 + this.MyInt2;
return hash;
}
}
public static bool operator==(MyClass a, MyClass b)
{
if (object.ReferenceEquals(a, null))
{
return object.ReferenceEquals(b, null);
}
return a.Equals(b);
}
// The != is based on the ==
public static bool operator!=(MyClass a, MyClass b)
{
return !(a == b);
}
public static bool operator>(MyClass a, MyClass b)
{
if (object.ReferenceEquals(a, null))
{
return false;
}
return a.CompareTo(b) > 0;
}
// The <, >=, <= are all based on the >
public static bool operator <(MyClass a, MyClass b)
{
return b > a;
}
public static bool operator >=(MyClass a, MyClass b)
{
//return !(a < b);
//We short-circuit the <operator, because we know how it's done
return !(b > a);
}
public static bool operator <=(MyClass a, MyClass b)
{
return !(a > b);
}
}
And this one is the variant for struct types. A lot shorter, because nearly all the object.ReferenceEquals(object, object) are gone. Value types can't be null.
public struct MyStruct : IComparable<MyStruct>, IComparable, IEquatable<MyStruct>
{
public int MyInt1 { get; set; }
public int MyInt2 { get; set; }
public int CompareTo(MyStruct other)
{
return this.InnerCompareTo(other);
}
int IComparable.CompareTo(object obj)
{
if (obj == null)
{
return 1;
}
if (!(obj is MyStruct))
{
throw new ArgumentException("obj");
}
MyStruct other = (MyStruct)obj;
return this.InnerCompareTo(other);
}
private int InnerCompareTo(MyStruct other)
{
int cmp = this.MyInt1.CompareTo(other.MyInt1);
if (cmp == 0)
{
cmp = this.MyInt2.CompareTo(other.MyInt2);
}
return cmp;
}
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if (!(obj is MyStruct))
{
throw new ArgumentException("obj");
}
MyStruct other = (MyStruct)obj;
return this.InnerEquals(other);
}
public bool Equals(MyStruct other)
{
return this.InnerEquals(other);
}
private bool InnerEquals(MyStruct other)
{
return this.MyInt1 == other.MyInt1 && this.MyInt2 == other.MyInt2;
}
public override int GetHashCode()
{
unchecked
{
// From http://stackoverflow.com/a/263416/613130
int hash = 17;
hash = hash * 23 + this.MyInt1;
hash = hash * 23 + this.MyInt2;
return hash;
}
}
// The != is based on the ==
public static bool operator ==(MyStruct a, MyStruct b)
{
return a.Equals(b);
}
public static bool operator !=(MyStruct a, MyStruct b)
{
return !(a == b);
}
public static bool operator >(MyStruct a, MyStruct b)
{
return a.CompareTo(b) > 0;
}
// The <, >=, <= are all based on the >
public static bool operator <(MyStruct a, MyStruct b)
{
return b > a;
}
public static bool operator >=(MyStruct a, MyStruct b)
{
//return !(a < b);
//We short-circuit the <operator, because we know how it's done
return !(b > a);
}
public static bool operator <=(MyStruct a, MyStruct b)
{
return !(a > b);
}
}

Categories