With two immutable classes Base and Derived (which derives from Base) I want to define Equality so that
equality is always polymorphic - that is ((Base)derived1).Equals((Base)derived2) will call Derived.Equals
operators == and != will call Equals rather than ReferenceEquals (value equality)
What I did:
class Base: IEquatable<Base> {
public readonly ImmutableType1 X;
readonly ImmutableType2 Y;
public Base(ImmutableType1 X, ImmutableType2 Y) {
this.X = X;
this.Y = Y;
}
public override bool Equals(object obj) {
if (object.ReferenceEquals(this, obj)) return true;
if (obj is null || obj.GetType()!=this.GetType()) return false;
return obj is Base o
&& X.Equals(o.X) && Y.Equals(o.Y);
}
public override int GetHashCode() => HashCode.Combine(X, Y);
// boilerplate
public bool Equals(Base o) => object.Equals(this, o);
public static bool operator ==(Base o1, Base o2) => object.Equals(o1, o2);
public static bool operator !=(Base o1, Base o2) => !object.Equals(o1, o2); }
Here everything ends up in Equals(object) which is always polymorphic so both targets are achieved.
I then derive like this:
class Derived : Base, IEquatable<Derived> {
public readonly ImmutableType3 Z;
readonly ImmutableType4 K;
public Derived(ImmutableType1 X, ImmutableType2 Y, ImmutableType3 Z, ImmutableType4 K) : base(X, Y) {
this.Z = Z;
this.K = K;
}
public override bool Equals(object obj) {
if (object.ReferenceEquals(this, obj)) return true;
if (obj is null || obj.GetType()!=this.GetType()) return false;
return obj is Derived o
&& base.Equals(obj) /* ! */
&& Z.Equals(o.Z) && K.Equals(o.K);
}
public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), Z, K);
// boilerplate
public bool Equals(Derived o) => object.Equals(this, o);
}
Which is basically the same except for one gotcha - when calling base.Equals I call base.Equals(object) and not base.Equals(Derived) (which will cause an endless recursion).
Also Equals(C) will in this implementation do some boxing/unboxing but that is worth it for me.
My questions are -
First is this correct ? my (testing) seems to suggest it is but with C# being so difficult in equality I'm just not sure anymore .. are there any cases where this is wrong ?
and Second - is this good ? are there better cleaner ways to achieve this ?
Well I guess there are two parts to you problem:
executing equals at nested level
restricting to the same type
Would this work? https://dotnetfiddle.net/eVLiMZ
(I had to use some older syntax as it didn't compile in dotnetfiddle otherwise)
using System;
public class Program
{
public class Base
{
public string Name { get; set; }
public string VarName { get; set; }
public override bool Equals(object o)
{
return object.ReferenceEquals(this, o)
|| o.GetType()==this.GetType() && ThisEquals(o);
}
protected virtual bool ThisEquals(object o)
{
Base b = o as Base;
return b != null
&& (Name == b.Name);
}
public override string ToString()
{
return string.Format("[{0}#{1} Name:{2}]", GetType(), VarName, Name);
}
public override int GetHashCode()
{
return Name.GetHashCode();
}
}
public class Derived : Base
{
public int Age { get; set; }
protected override bool ThisEquals(object o)
{
var d = o as Derived;
return base.ThisEquals(o)
&& d != null
&& (d.Age == Age);
}
public override string ToString()
{
return string.Format("[{0}#{1} Name:{2} Age:{3}]", GetType(), VarName, Name, Age);
}
public override int GetHashCode()
{
return base.GetHashCode() ^ Age.GetHashCode();
}
}
public static void Main()
{
var b1 = new Base { Name = "anna", VarName = "b1" };
var b2 = new Base { Name = "leo", VarName = "b2" };
var b3 = new Base { Name = "anna", VarName = "b3" };
var d1 = new Derived { Name = "anna", Age = 21, VarName = "d1" };
var d2 = new Derived { Name = "anna", Age = 12, VarName = "d2" };
var d3 = new Derived { Name = "anna", Age = 21, VarName = "d3" };
var all = new object [] { b1, b2, b3, d1, d2, d3 };
foreach(var a in all)
{
foreach(var b in all)
{
Console.WriteLine("{0}.Equals({1}) => {2}", a, b, a.Equals(b));
}
}
}
}
This method of comparison using Reflection which, other than the extension methods, is simpler. It also keeps private members private.
All of the logic is in the IImmutableExtensions class. It simply looks at what fields are readonly and uses them for the comparison.
You don't need methods in the base or derived classes for the object comparison. Just call the extension method ImmutableEquals when you are overriding ==, !=, and Equals(). Same with the hashcode.
public class Base : IEquatable<Base>, IImmutable
{
public readonly ImmutableType1 X;
readonly ImmutableType2 Y;
public Base(ImmutableType1 X, ImmutableType2 Y) => (this.X, this.Y) = (X, Y);
// boilerplate
public override bool Equals(object obj) => this.ImmutableEquals(obj);
public bool Equals(Base o) => this.ImmutableEquals(o);
public static bool operator ==(Base o1, Base o2) => o1.ImmutableEquals(o2);
public static bool operator !=(Base o1, Base o2) => !o1.ImmutableEquals(o2);
private int? _hashCache;
public override int GetHashCode() => this.ImmutableHash(ref _hashCache);
}
public class Derived : Base, IEquatable<Derived>, IImmutable
{
public readonly ImmutableType3 Z;
readonly ImmutableType4 K;
public Derived(ImmutableType1 X, ImmutableType2 Y, ImmutableType3 Z, ImmutableType4 K) : base(X, Y) => (this.Z, this.K) = (Z, K);
public bool Equals(Derived other) => this.ImmutableEquals(other);
}
And the IImmutableExtensions class:
public static class IImmutableExtensions
{
public static bool ImmutableEquals(this IImmutable o1, object o2)
{
if (ReferenceEquals(o1, o2)) return true;
if (o2 is null || o1.GetType() != o2.GetType() || o1.GetHashCode() != o2.GetHashCode()) return false;
foreach (var tProp in GetImmutableFields(o1))
{
var test = tProp.GetValue(o1)?.Equals(tProp.GetValue(o2));
if (test is null) continue;
if (!test.Value) return false;
}
return true;
}
public static int ImmutableHash(this IImmutable o, ref int? hashCache)
{
if (hashCache is null)
{
hashCache = 0;
foreach (var tProp in GetImmutableFields(o))
{
hashCache = HashCode.Combine(hashCache.Value, tProp.GetValue(o).GetHashCode());
}
}
return hashCache.Value;
}
private static IEnumerable<FieldInfo> GetImmutableFields(object o)
{
var t = o.GetType();
do
{
var fields = t.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public).Where(field => field.IsInitOnly);
foreach(var field in fields)
{
yield return field;
}
}
while ((t = t.BaseType) != typeof(object));
}
}
Old answer: (I will leave this for reference)
Based on what you were saying about having to cast to object it occurred to me that the methods Equals(object) and Equals(Base) were too ambiguous when calling them from a derived class.
This said to me that the logic should be moved out of both of the classes, to a method that would better describe our intentions.
Equality will remain polymorphic as ImmutableEquals in the base class will call the overridden ValuesEqual. This is where you can decide in each derived class how to compare equality.
This is your code refactored with that goal.
Revised answer:
It occurred to me that all of our logic in IsEqual() and GetHashCode() would work if we simply supplied a tuple that contained the immutable fields that we wanted to compare. This avoids duplicating so much code in every class.
It is up to the developer that creates the derived class to override GetImmutableTuple(). Without using reflection (see other answer), I feel this is the least of all evils.
public class Base : IEquatable<Base>, IImmutable
{
public readonly ImmutableType1 X;
readonly ImmutableType2 Y;
public Base(ImmutableType1 X, ImmutableType2 Y) =>
(this.X, this.Y) = (X, Y);
protected virtual IStructuralEquatable GetImmutableTuple() => (X, Y);
// boilerplate
public override bool Equals(object o) => IsEqual(o as Base);
public bool Equals(Base o) => IsEqual(o);
public static bool operator ==(Base o1, Base o2) => o1.IsEqual(o2);
public static bool operator !=(Base o1, Base o2) => !o1.IsEqual(o2);
public override int GetHashCode() => hashCache is null ? (hashCache = GetImmutableTuple().GetHashCode()).Value : hashCache.Value;
protected bool IsEqual(Base obj) => ReferenceEquals(this, obj) || !(obj is null) && GetType() == obj.GetType() && GetHashCode() == obj.GetHashCode() && GetImmutableTuple() != obj.GetImmutableTuple();
protected int? hashCache;
}
public class Derived : Base, IEquatable<Derived>, IImmutable
{
public readonly ImmutableType3 Z;
readonly ImmutableType4 K;
public Derived(ImmutableType1 X, ImmutableType2 Y, ImmutableType3 Z, ImmutableType4 K) : base(X, Y) =>
(this.Z, this.K) = (Z, K);
protected override IStructuralEquatable GetImmutableTuple() => (base.GetImmutableTuple(), K, Z);
// boilerplate
public bool Equals(Derived o) => IsEqual(o);
}
The code can be simplified using a combination of an extension method and some boilercode. This takes almost all of the pain away and leaves classes focused on comparing their instances without having to deal with all the special edge cases:
namespace System {
public static partial class ExtensionMethods {
public static bool Equals<T>(this T inst, object obj, Func<T, bool> thisEquals) where T : IEquatable<T> =>
object.ReferenceEquals(inst, obj) // same reference -> equal
|| !(obj is null) // this is not null but obj is -> not equal
&& obj.GetType() == inst.GetType() // obj is more derived than this -> not equal
&& obj is T o // obj cannot be cast to this type -> not equal
&& thisEquals(o);
}
}
I can now do:
class Base : IEquatable<Base> {
public SomeType1 X;
SomeType2 Y;
public Base(SomeType1 X, SomeType2 Y) => (this.X, this.Y) = (X, Y);
public bool ThisEquals(Base o) => (X, Y) == (o.X, o.Y);
// boilerplate
public override bool Equals(object obj) => this.Equals(obj, ThisEquals);
public bool Equals(Base o) => object.Equals(this, o);
public static bool operator ==(Base o1, Base o2) => object.Equals(o1, o2);
public static bool operator !=(Base o1, Base o2) => !object.Equals(o1, o2);
}
class Derived : Base, IEquatable<Derived> {
public SomeType3 Z;
SomeType4 K;
public Derived(SomeType1 X, SomeType2 Y, SomeType3 Z, SomeType4 K) : base(X, Y) => (this.Z, this.K) = (Z, K);
public bool ThisEquals(Derived o) => base.ThisEquals(o) && (Z, K) == (o.Z, o.K);
// boilerplate
public override bool Equals(object obj) => this.Equals(obj, ThisEquals);
public bool Equals(Derived o) => object.Equals(this, o);
}
This is good, no casting or null checks and all the real work is clearly separated in ThisEquals.(testing)
For immutable classes it is possible to optimize further by caching the hashcode and using it in Equals to shortcut equality if the hashcodes are different:
namespace System.Immutable {
public interface IImmutableEquatable<T> : IEquatable<T> { };
public static partial class ExtensionMethods {
public static bool ImmutableEquals<T>(this T inst, object obj, Func<T, bool> thisEquals) where T : IImmutableEquatable<T> =>
object.ReferenceEquals(inst, obj) // same reference -> equal
|| !(obj is null) // this is not null but obj is -> not equal
&& obj.GetType() == inst.GetType() // obj is more derived than this -> not equal
&& inst.GetHashCode() == obj.GetHashCode() // optimization, hash codes are different -> not equal
&& obj is T o // obj cannot be cast to this type -> not equal
&& thisEquals(o);
public static int GetHashCode<T>(this T inst, ref int? hashCache, Func<int> thisHashCode) where T : IImmutableEquatable<T> {
if (hashCache is null) hashCache = thisHashCode();
return hashCache.Value;
}
}
}
I can now do:
class Base : IImmutableEquatable<Base> {
public readonly SomeImmutableType1 X;
readonly SomeImmutableType2 Y;
public Base(SomeImmutableType1 X, SomeImmutableType2 Y) => (this.X, this.Y) = (X, Y);
public bool ThisEquals(Base o) => (X, Y) == (o.X, o.Y);
public int ThisHashCode() => (X, Y).GetHashCode();
// boilerplate
public override bool Equals(object obj) => this.ImmutableEquals(obj, ThisEquals);
public bool Equals(Base o) => object.Equals(this, o);
public static bool operator ==(Base o1, Base o2) => object.Equals(o1, o2);
public static bool operator !=(Base o1, Base o2) => !object.Equals(o1, o2);
protected int? hashCache;
public override int GetHashCode() => this.GetHashCode(ref hashCache, ThisHashCode);
}
class Derived : Base, IImmutableEquatable<Derived> {
public readonly SomeImmutableType3 Z;
readonly SomeImmutableType4 K;
public Derived(SomeImmutableType1 X, SomeImmutableType2 Y, SomeImmutableType3 Z, SomeImmutableType4 K) : base(X, Y) => (this.Z, this.K) = (Z, K);
public bool ThisEquals(Derived o) => base.ThisEquals(o) && (Z, K) == (o.Z, o.K);
public new int ThisHashCode() => (base.ThisHashCode(), Z, K).GetHashCode();
// boilerplate
public override bool Equals(object obj) => this.ImmutableEquals(obj, ThisEquals);
public bool Equals(Derived o) => object.Equals(this, o);
public override int GetHashCode() => this.GetHashCode(ref hashCache, ThisHashCode);
}
Which is not too bad - there is more complexity but it is all just boilerplate which I just cut&paste .. the logic is clearly separated in ThisEquals and ThisHashCode
(testing)
Another method would be to use Reflection to automatically compare all of your fields and properties. You just have to decorate them with the Immutable attribute and AutoCompare() will take care of the rest.
This will also use Reflection to build a HashCode based on your fields and properties decorated with Immutable, and then cache it to optimize the object comparison.
public class Base : ComparableImmutable, IEquatable<Base>, IImmutable
{
[Immutable]
public ImmutableType1 X { get; set; }
[Immutable]
readonly ImmutableType2 Y;
public Base(ImmutableType1 X, ImmutableType2 Y) => (this.X, this.Y) = (X, Y);
public bool Equals(Base o) => AutoCompare(o);
}
public class Derived : Base, IEquatable<Derived>, IImmutable
{
[Immutable]
public readonly ImmutableType3 Z;
[Immutable]
readonly ImmutableType4 K;
public Derived(ImmutableType1 X, ImmutableType2 Y, ImmutableType3 Z, ImmutableType4 K)
: base(X, Y)
=> (this.Z, this.K) = (Z, K);
public bool Equals(Derived o) => AutoCompare(o);
}
[AttributeUsage(validOn: AttributeTargets.Field | AttributeTargets.Property)]
public class ImmutableAttribute : Attribute { }
public abstract class ComparableImmutable
{
static BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly;
protected int? hashCache;
public override int GetHashCode()
{
if (hashCache is null)
{
hashCache = 0;
var type = GetType();
do
{
foreach (var field in type.GetFields(flags).Where(field => Attribute.IsDefined(field, typeof(ImmutableAttribute))))
hashCache = HashCode.Combine(hashCache, field.GetValue(this));
foreach (var property in type.GetProperties(flags).Where(property => Attribute.IsDefined(property, typeof(ImmutableAttribute))))
hashCache = HashCode.Combine(hashCache, property.GetValue(this));
type = type.BaseType;
}
while (type != null);
}
return hashCache.Value;
}
protected bool AutoCompare(object obj2)
{
if (ReferenceEquals(this, obj2)) return true;
if (obj2 is null
|| GetType() != obj2.GetType()
|| GetHashCode() != obj2.GetHashCode())
return false;
var type = GetType();
do
{
foreach (var field in type.GetFields(flags).Where(field => Attribute.IsDefined(field, typeof(ImmutableAttribute))))
{
if (field.GetValue(this) != field.GetValue(obj2))
{
return false;
}
}
foreach (var property in type.GetProperties(flags).Where(property => Attribute.IsDefined(property, typeof(ImmutableAttribute))))
{
if (property.GetValue(this) != property.GetValue(obj2))
{
return false;
}
}
type = type.BaseType;
}
while (type != null);
return true;
}
public override bool Equals(object o) => AutoCompare(o);
public static bool operator ==(Comparable o1, Comparable o2) => o1.AutoCompare(o2);
public static bool operator !=(Comparable o1, Comparable o2) => !o1.AutoCompare(o2);
}
Related
I have two almost the same two structs, only different implement Equals method
I don't want to use class but... I want to abstract equality.
Should I use the interface? I'd like your advice.
public readonly struct AStruct : IEquatable<AStruct>
{
[Pure]
public bool Equals(AStruct other) =>
... AStruct Equals implementation
[Pure]
public override bool Equals(object obj) =>
obj is AStruct other && Equals(other);
[Pure]
public override int GetHashCode()
{
...
}
... other methods
}
public readonly struct BStruct : IEquatable<BStruct>
{
[Pure]
public bool Equals(BStruct other) =>
... BStruct Equals implementation
[Pure]
public override bool Equals(object obj) =>
obj is BStruct other && Equals(other);
[Pure]
public override int GetHashCode()
{
...
}
... other methods
}
If those structs are basically same, but you have them both to provide two ways to compare them, so different Equals implementations, i would suggest to use one struct but two IEqualityComparer<T>. Say this struct is now AB_Struct(one for both):
public class AB_Comparer_1 : IEqualityComparer<AB_Struct>
{
public bool Equals(AB_Struct x, AB_Struct y)
{
// TODO...
}
public int GetHashCode(AB_Struct obj)
{
// TODO...
}
}
public class AB_Comparer_2 : IEqualityComparer<AB_Struct>
{
public bool Equals(AB_Struct x, AB_Struct y)
{
// TODO...
}
public int GetHashCode(AB_Struct obj)
{
// TODO...
}
}
You can now use whatever comparer you need, for most compare or LINQ methods. For example:
if (items1.Intersect(items2, new AB_Comparer_1()).Any())
{
// TODO ...
}
or as dictionary key comparer:
var dict = new Dictionary<AB_Struct, int>(new AB_Comparer_2());
Motivation
I'm looking to implement IComparer<> in a similar way to the demo code below. Where Foo is the type of objects I need to compare. It does not implement IComparable, but I'm providing an IComparer class for each field so the user can elect to equate to instances based on one field value.
enum Day {Sat, Sun, Mon, Tue, Wed, Thu, Fri};
class Foo {
public int Bar;
public string Name;
public Day Day;
}
Comparer classes are:
// Compares all fields in Foo
public class FooComparer : IEqualityComparer<Foo>
{
public bool Equals(Foo x, Foo y)
{
if (ReferenceEquals(x, y)) return true;
return x.Bar == y.Bar && x.Name == y.Name && return x.Day == y.Day;
}
public int GetHashCode(Foo obj)
{
unchecked
{
var hashCode = obj.Bar;
hashCode = (hashCode * 397) ^ (obj.Name != null ? obj.Name.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (int) obj.Day; 0);
return hashCode;
}
}
}
// Compares only in Foo.Bar
public class FooBarComparer : IEqualityComparer<Foo>
{
public bool Equals(Foo x, Foo y)
{
if (ReferenceEquals(x, y)) return true;
return x.Bar == y.Bar;
}
public int GetHashCode(Foo obj)
{
unchecked
{
var hashCode = obj.Bar;
hashCode = (hashCode * 397) ^ (obj.Name != null ? obj.Name.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (int) obj.Day; 0);
return hashCode;
}
}
}
// Compares only in Foo.Name
public class FooNameComparer : IEqualityComparer<Foo>
{
public bool Equals(Foo x, Foo y)
{
if (ReferenceEquals(x, y)) return true;
return x.Name == y.Name;
}
public int GetHashCode(Foo obj)
{
unchecked
{
var hashCode = obj.Bar;
hashCode = (hashCode * 397) ^ (obj.Name != null ? obj.Name.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (int) obj.Day; 0);
return hashCode;
}
}
}
// Compares only in Foo.Day
public class FooDayComparer : IEqualityComparer<Foo>
{
public bool Equals(Foo x, Foo y)
{
if (ReferenceEquals(x, y)) return true;
return x.Day == y.Day;
}
public int GetHashCode(Foo obj)
{
unchecked
{
var hashCode = obj.Bar;
hashCode = (hashCode * 397) ^ (obj.Name != null ? obj.Name.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (int) obj.Day; 0);
return hashCode;
}
}
}
Question
I want to allow the user to be able to combine multiple Comparer types to evaluate two instances of Type Foo. I'm not sure how to do that.
Idea
What I came up with is something like this, where I AND the results of comparisons done by all comparers in the list:
bool CompareFoo(Foo a, Foo b, params IComparer[] comparers)
{
bool isEqual = true;
// Or the list and return;
foreach (var comparer in comparers)
{
isEqual = isEqual && comparer.Equals(x,y);
}
return isEqual;
}
Notes
My target .NET version is 4.5.
I may be stuck with C# 5.0.
Also, may be stuck with `MSBuild 12.0
This is my first time to use IComparer.
You can combine multiple IEqualityComparer<Foo> objects by defining an additional comparer that takes other comparers as constructor parameters:
public class CompositeFooComparer : IEqualityComparer<Foo>
{
private IEqualityComparer<Foo>[] comparers;
public CompositeFooComparer(params IEqualityComparer<Foo>[] comparers)
{
this.comparers = comparers;
}
public bool Equals(Foo x, Foo y)
{
foreach (var comparer in comparers)
{
if (!comparer.Equals(x, y))
{
return false;
}
}
return true;
}
public int GetHashCode(Foo obj)
{
var hash = 0;
foreach (var comparer in comparers)
{
hash = hash * 17 + (comparer.GetHashCode(obj));
}
return hash;
}
}
Then you can create and use it like this:
var fooA = new Foo
{
Bar = 5,
Day = Day.Fri,
Name = "a"
};
var fooB = new Foo
{
Bar = 5,
Day = Day.Fri,
Name = "b"
};
var barComparer = new FooBarComparer();
var dayComparer = new FooDayComparer();
var compositeComparer = new CompositeFooComparer(barComparer, dayComparer);
Console.WriteLine(compositeComparer.Equals(fooA, fooB)); // displays "true"
Another idea is to have a comparer that does know which fields will be compared, based on boolean parameters instead.
public class ConfigurableFooComparer : IEqualityComparer<Foo>
{
private readonly bool compareBar;
private readonly bool compareName;
private readonly bool compareDay;
public ConfigurableFooComparer(bool compareBar, bool compareName, bool compareDay)
{
this.compareBar = compareBar;
this.compareName = compareName;
this.compareDay = compareDay;
}
public bool Equals(Foo x, Foo y)
{
if (ReferenceEquals(x, y))
{
return true;
}
if (x == null || y == null)
{
return false;
}
if (compareBar && x.Bar != y.Bar)
{
return false;
}
if (compareName && x.Name != y.Name)
{
return false;
}
if (compareDay && x.Day != y.Day)
{
return false;
}
return true;
}
public int GetHashCode(Foo obj)
{
unchecked
{
var hash = 0;
if (compareBar)
{
hash = hash * 17 + obj.Bar.GetHashCode();
}
if (compareName)
{
hash = hash * 17 + (obj.Name == null ? 0 : obj.Name.GetHashCode());
}
if (compareDay)
{
hash = hash * 17 + obj.Day.GetHashCode();
}
return hash;
}
}
And then using it like this:
var barAndDayComparer = new ConfigurableFooComparer(compareBar: true, compareName: false, compareDay: true);
Console.WriteLine(barAndDayComparer.Equals(fooA, fooB));
It seems to me that what you are trying to achieve feels very similar to a Chain-of-responsibility.
So why don't you arrange all your Foo comparers in a chain-like structure and make the chain extensible so that new links can be added at run-time?
Here's is the idea:
the client will implement whatever Foo comparers it wants and all of them will be neatly arranged in a way that all of them will be called one by one and if anyone returns false then the whole comparison returns false!
Here's the code:
public abstract class FooComparer
{
private readonly FooComparer _next;
public FooComparer(FooComparer next)
{
_next = next;
}
public bool CompareFoo(Foo a, Foo b)
{
return AreFoosEqual(a, b)
&& (_next?.CompareFoo(a, b) ?? true);
}
protected abstract bool AreFoosEqual(Foo a, Foo b);
}
public class FooNameComparer : FooComparer
{
public FooNameComparer(FooComparer next) : base(next)
{
}
protected override bool AreFoosEqual(Foo a, Foo b)
{
return a.Name == b.Name;
}
}
public class FooBarComparer : FooComparer
{
public FooBarComparer(FooComparer next) : base(next)
{
}
protected override bool AreFoosEqual(Foo a, Foo b)
{
return a.Bar == b.Bar;
}
}
The idea of the FooComparer abstract class is having something like a chain manager; it handles the calling of the whole chain and forces its derived classes to implement the code to compare the Foo's, all while exposing the method CompareFoo which is what the client will use.
And how will the client use it? well it can do something like this:
var manager = new FooManager();
manager.FooComparer
= new FooNameComparer(new FooBarComparer(null));
manager.FooComparer.CompareFoo(fooA, fooB);
But it's cooler if they can register the FooComparer chain to the IoC Container!
Edit
This is a more simplistic approach I've been using for a while to custom compare things:
public class GenericComparer<T> : IEqualityComparer<T> where T : class
{
private readonly Func<T, object> _identitySelector;
public GenericComparer(Func<T, object> identitySelector)
{
_identitySelector = identitySelector;
}
public bool Equals(T x, T y)
{
var first = _identitySelector.Invoke(x);
var second = _identitySelector.Invoke(y);
return first != null && first.Equals(second);
}
public int GetHashCode(T obj)
{
return _identitySelector.Invoke(obj).GetHashCode();
}
}
public bool CompareFoo2(Foo a, Foo b, params IEqualityComparer<Foo>[] comparers)
{
foreach (var comparer in comparers)
{
if (!comparer.Equals(a, b))
{
return false;
}
}
return true;
}
And let the client do:
var areFoosEqual = CompareFoo2(a, b,
new GenericComparer<Foo>(foo => foo.Name),
new GenericComparer<Foo>(foo => foo.Bar))
It may be possible to adapt the GenericComparer to have multiple identity selector as to pass them all in a single lambda but we would also need to update its GetHashCode method to compute the HashCode correctly using all the identity objects.
You can achieve by something like this :
class Program
{
static bool CompareFoo(Foo a, Foo b, List<IEqualityComparer<Foo>> comparers)
{
return comparers.All(com => com.Equals(a, b));
}
static void Main(string[] args)
{
List<IEqualityComparer<Foo>> compares = new List<IEqualityComparer<Foo>>
{
new FooNameComparer(),
new FooBarComparer()
};
var test1 = CompareFoo(new Foo { Name = "aio", Bar = 10 }, new Foo { Name = "aio", Bar = 10 }, compares);
var test2 = CompareFoo(new Foo { Name = "Foo1", Bar = 10 }, new Foo { Name = "Foo2", Bar = 10 }, compares);
}
}
Note : you must consider all possible conditions in your compare classes, for example in "FooNameComparer" class the below code can become a bug :
return x.Name == y.Name;
because if the "Name" property of two classes pass null, null == null return true! the code should be :
public bool Equals(Foo x, Foo y)
{
if (ReferenceEquals(x, y)) return true;
if (string.IsNullOrEmpty(x?.Name) || string.IsNullOrEmpty(y?.Name))
return false;
return x.Name == y.Name;
}
I have a dictionary:
Dictionary<HashSet<myClass>, List<MyObj>> myDict = ...
And I have:
HashSet<myClass> myHashSet = ...
I want to check if the dictionary (myDict) contains myHashSet.
I tried to override two methods:
1) equal
2) GetHashCode
public class myClass
{
public string id;
public int number;
public override bool Equals(object obj)
{
myClass other = obj as myClass;
bool ret = false;
if (other != null)
{
ret = (this.number == other.number) && (this.id == other.id);
}
return ret;
}
public override int GetHashCode()
{
return this.number ^ this.id.GetHashCode();
}
};
Unfortunately, a key that is found in dictionary, returns false for the code:
myDict.ContainsKey(myHashSet)
Any help appreciated!
Just because you overrode myClass's Equals( and GetHashCode() does not mean that that you overrode HashSet<myClass>'s Equals( and GetHashCode(), that is what is being used when you do the dictionary lookup.
If you want it to work you need to pass a IEqualityComparer<HashSet<myClass>> in to the constructor of the dictionary so it will use that comparer when doing the dictionary lookup.
public class myClassSetComperer : IEqualityComparer<HashSet<myClass>>
{
public bool Equals(HashSet<myClass> x, HashSet<myClass> y)
{
if (ReferenceEquals(x, y)) return true;
if (ReferenceEquals(null, x)) return false;
if (ReferenceEquals(null, y)) return false;
return x.SetEquals(y);
}
public int GetHashCode(HashSet<myClass> obj)
{
unchecked
{
int x = 0;
foreach (var myClass in obj)
{
x = (x*397) ^ myClass?.GetHashCode() ?? 0;
}
return x;
}
}
}
//elsewhere
Dictionary<HashSet<myClass>, List<MyObj>> myDict = new Dictionary<HashSet<myClass>, List<MyObj>>(new myClassSetComperer());
VERY IMPORTANT NOTE: Dictionary keys (and hash sets) break horribly if you do anything that causes Equals( or GetHashCode() to change once put in as the lookup key. If you modify the HashSet<myClass> or one of the myClass objects after you put it in the dictionary you will break the dictionary and potentially the HashSet. See this very good blog post by Eric Lippert on "Guidelines and rules for GetHashCode"
overriding the GetHasCode and Equal is when comparing instances of myClass.
Here's a sample of using ContainsKey, which is checking by objects reference.
Dictionary<HashSet<string>, List<string>> hashSetDictionary = new Dictionary<HashSet<string>, List<string>>();
var myHashSet = new HashSet<string>();
hashSetDictionary.Add(myHashSet, null);
Console.WriteLine(hashSetDictionary.ContainsKey(myHashSet));
Here's an update to your code
public class myClass
{
public myClass(string text, int num)
{
this.Text = text;
this.Num = num;
}
public string Text { get; set; }
public int Num { get; set; }
}
public class MyObj { }
public class AlwaysTrueHashSet<T> : HashSet<T>
{
public override bool Equals(object obj)
{
return this.GetHashCode() == obj.GetHashCode();
}
public override int GetHashCode()
{
return "Counting hashcode".GetHashCode();
}
}
class Program
{
static void Main(string[] args)
{
Dictionary<HashSet<myClass>, List<MyObj>> myDict = new Dictionary<HashSet<myClass>,
List<MyObj>>();
var myHashSet1 = new AlwaysTrueHashSet<myClass>();
myHashSet1.Add(new myClass("123", 5));
myDict.Add(myHashSet1, null);
var myHashSet2 = new AlwaysTrueHashSet<myClass>();
myHashSet2.Add(new myClass("123", 5));
/*
* when containsKey is invoked, it's checking if the reference of myHashSet2 is the same as myHashSet1.
* That's the default behavior.
*
* extend HashSet, and override the gethashcode and equal methods
*/
if (myDict.ContainsKey(myHashSet2))
{
Console.WriteLine("in");
int i = 3; // it doesn't get this line }
}
}
}
The following prints equals:
struct A
{
int x;
public A(int _x) { x = _x; }
public int Y
{
get
{
Random r = new Random();
return r.Next(0, 1000);
}
}
}
static void Main(string[] args)
{
A a1 = new A(1),a2 = new A(1);
if (a1.Equals(a2))
{
Console.Write("Equals");
}
else
{
Console.Write("Different");
}
}
Is there anyway to get C# to return false in that case? Meaning, to take the properties under consideration when comparing value types?
Write equal then hit "tab" button twice:
// override object.Equals
public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
{
return false;
}
// TODO: write your implementation of Equals() here
throw new NotImplementedException();
return base.Equals(obj);
}
This is an automatically generated snippet. Now you can try something like:
// override object.Equals
public override bool Equals(object obj)
{
// checks for A versus A
if (obj == null || GetType() != obj.GetType())
{
return false;
}
// TODO: write your implementation of Equals() here
throw new NotImplementedException();
int compareThis=(A)obj.x;
return ((A)base).x==compareThis; // maybe casting is not needed
}
The recommended approach is to use IEquatable<T> instead of using the default inherited Equals method. The IEquatable generic interface defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.
using System;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
A a1 = new A(1), a2 = new A(1);
//here the CLR will do a lot of unboxing and check operations via reflection in order to make a comparaison between fields value.
//just take a look bellow at the decompiled default Equals method how it's done
if (a1.Equals(a2))
{
Console.Write("Equals");
}
else
{
Console.Write("Different");
}
}
}
public struct A : IEquatable<A>
{
int x;
public A(int _x) { x = _x; }
public int Y
{
get
{
Random r = new Random();
return r.Next(0, 1000);
}
}
//here no boxing or unboxing is needed even if is a value type and the CLR will call this method first
public bool Equals(A other)
{
return this.Y == other.Y;
}
public override bool Equals(object obj)
{
//this is why a bad approach to compare both objects you need to unbox the struct arguments wich hurting performance
return this.Y == ((A)obj).Y;
}
public override int GetHashCode()
{
return base.GetHashCode();
}
//default implementation
//public override bool Equals(object obj)
//{
// return base.Equals(obj);
//}
}
}
CLR Implementation
The CLR what's going underneath
public override bool Equals(object obj)
{
if (obj == null)
return false;
RuntimeType runtimeType = (RuntimeType) this.GetType();
if ((RuntimeType) obj.GetType() != runtimeType)
return false;
object a = (object) this;
if (ValueType.CanCompareBits((object) this))
return ValueType.FastEqualsCheck(a, obj);
FieldInfo[] fields = runtimeType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
for (int index = 0; index < fields.Length; ++index)
{
object obj1 = ((RtFieldInfo) fields[index]).UnsafeGetValue(a);
object obj2 = ((RtFieldInfo) fields[index]).UnsafeGetValue(obj);
if (obj1 == null)
{
if (obj2 != null)
return false;
}
else if (!obj1.Equals(obj2))
return false;
}
return true;
}
This is very similar to this question.
All you need to do is to override the Equals method:
struct A
{
int x;
public A(int _x) { x = _x; }
public int Y
{
get
{
Random r = new Random();
return r.Next(0, 1000);
}
}
public override bool Equals(object obj)
{
//compare whatever you want...
}
}
}
Override equal method and return true or false based on property comparison.
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);
}
}