CSharp · Console
using System;
using System.Immutable;
namespace System.Immutable {
public interface IImmutableEquatable<T> : IEquatable<T> { };
public static partial class ExtensionMethods {
public static bool Equals<T>(this T inst, object obj, Func<T, bool> thisEquals) where T : IImmutableEquatable<T> {
Console.WriteLine($" Equals Extention Method typeof(T)=={typeof(T).ToString()} , inst.GetType()=={inst.GetType().ToString()} , obj.GetType()=={(obj is null ? "null" : obj.GetType().ToString())}");
return object.ReferenceEquals(inst, obj) // same reference -> equal
|| !(obj is null) // this is not null but obj is -> not equal
&& inst.GetType() == obj.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> {
Console.WriteLine(" Extention Method GetHashCode " + typeof(T).ToString());
if (hashCache is null) hashCache = thisHashCode();
return hashCache.Value;
}
}
}
class Base : IImmutableEquatable<Base> {
public readonly int X;
readonly int Y;
public Base(int X, int Y) {
this.X = X;
this.Y = Y;
}
public bool ThisEquals(Base o) {
Console.WriteLine(" Base ThisEquals");
return X.Equals(o.X) && Y.Equals(o.Y);
}
public int ThisHashCode() {
Console.WriteLine(" Base ThisGetHashCode");
return Tuple.Create(X, Y).GetHashCode();
}
// boilerplate
public override bool Equals(object o) { Console.WriteLine(" Base.Equals(object)"); return this.Equals(o, ThisEquals); }
public bool Equals(Base o) { Console.WriteLine(" Base.Equals(Base)"); return object.Equals(this, o); }
public static bool operator ==(Base o1, Base o2) { Console.WriteLine(" Base=="); return object.Equals(o1, o2); }
public static bool operator !=(Base o1, Base o2) { Console.WriteLine(" Base!="); return !object.Equals(o1, o2); }
protected int? hashCache;
public override int GetHashCode() => this.GetHashCode(ref hashCache, ThisHashCode);
}
class Derived : Base, IImmutableEquatable<Derived> {
public readonly int Z;
readonly int K;
public Derived(int X, int Y, int Z, int K) : base(X, Y) {
this.Z = Z;
this.K = K;
}
public bool ThisEquals(Derived o) {
Console.WriteLine(" Derived ThisEquals");
return base.ThisEquals(o) && Z.Equals(o.Z) && K.Equals(o.K);
}
public new int ThisHashCode() {
Console.WriteLine(" Derived ThisGetHashCode");
return Tuple.Create(base.ThisHashCode(), Z, K).GetHashCode();
}
// boilerplate
public override bool Equals(object o) { Console.WriteLine(" Derived.Equals(object)"); return this.Equals(o, ThisEquals); }
public bool Equals(Derived o) { Console.WriteLine(" Derived.Equals(Derived)"); return object.Equals(this, o); }
public override int GetHashCode() => this.GetHashCode(ref hashCache, ThisHashCode);
}
public class Program {
public static void Main() {
Derived d1 = new Derived(0, 1, 2, 3), d2 = new Derived(0, 1, 4, 5), d3 = new Derived(0, 1, 2, 3), d4 = null;
Base b1 = d1, b2 = d2, b3 = d3, b4 = d4, b5 = null;
Console.WriteLine("d1==d2"); Console.WriteLine(" " + (d1 == d2));
Console.WriteLine("\nd1.Equals(d2)"); Console.WriteLine(" " + d1.Equals(d2) + "\n");
Console.WriteLine("\nd1==d3"); Console.WriteLine(" " + (d1 == d3));
Console.WriteLine("\nd1.Equals(d3)"); Console.WriteLine(" " + d1.Equals(d3) + "\n");
Console.WriteLine("\nd1==d4"); Console.WriteLine(" " + (d1 == d4));
Console.WriteLine("\nd1.Equals(d4)"); Console.WriteLine(" " + d1.Equals(d4) + "\n");
Console.WriteLine("\nb1==b2"); Console.WriteLine(" " + (b1 == b2));
Console.WriteLine("\nb1.Equals(b2)"); Console.WriteLine(" " + b1.Equals(b2) + "\n");
Console.WriteLine("\nb1==b3"); Console.WriteLine(" " + (b1 == b3));
Console.WriteLine("\nb1.Equals(b3)"); Console.WriteLine(" " + b1.Equals(b3) + "\n");
Console.WriteLine("\nb1==b4"); Console.WriteLine(" " + (b1 == b4));
Console.WriteLine("\nb1.Equals(b4)"); Console.WriteLine(" " + b1.Equals(b4) + "\n");
Base b = new Base(0, 1);
Console.WriteLine("\nb==d1"); Console.WriteLine(" " + (b == b1));
Console.WriteLine("\nb.Equals(d1)"); Console.WriteLine(" " + b.Equals(d1) + "\n");
Console.WriteLine("\nb5==d1"); Console.WriteLine(" " + (b5 == d1));
Console.WriteLine("\nb5==d4"); Console.WriteLine(" " + (b5 == d4));
}
}