public static partial class ExtensionMethods {
public static bool Equals<TSrc, TBase>(this TSrc inst, object obj, Func<TSrc, bool> f) where TSrc : IEquatable<TSrc>, TBase where TBase : class {
if (object.ReferenceEquals(inst, obj)) return true;
if (obj is null) return false;
if (!(obj is TSrc o)) return false;
if (obj.GetType() != inst.GetType()) return false;
if (inst.GetHashCode() != o.GetHashCode()) return false;
if (typeof(TBase) != typeof(Object) && !((inst as TBase).Equals(obj))) return false;
class Base: IEquatable<Base> {
public Base(int X, int Y) {
public override bool Equals(object obj) {
return this.Equals<Base, Object>(obj, o =>
X.Equals(o.X) && Y.Equals(o.Y));
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);
public override int GetHashCode() => X ^ Y;
class Derived : Base, IEquatable<Derived> {
public Derived(int X, int Y, int Z, int K) : base(X, Y) {
public override bool Equals(object obj) {
return this.Equals<Derived, Base>(obj, o =>
Z.Equals(o.Z) && K.Equals(o.K));
public bool Equals(Derived o) => object.Equals(this, o);
public static bool operator ==(Derived o1, Derived o2) => object.Equals(o1, o2);
public static bool operator !=(Derived o1, Derived o2) => !object.Equals(o1, o2);
public override int GetHashCode() => base.GetHashCode() ^ Z ^ K;
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;
Console.WriteLine(" d1==d2 => "+ (d1==d2));
Console.WriteLine(" d1.Equals(d2) => " + (d1.Equals(d2)));
Console.WriteLine(" d1==d3 => " + (d1==d3));
Console.WriteLine(" d1.Equals(d3) => " + (d1.Equals(d3)));
Console.WriteLine(" d1==d4 => " + (d1 == d4));
Console.WriteLine(" d1.Equals(d4) => " + (d1.Equals(d4)));
Console.WriteLine(" b1==b2 => "+ (b1==b2));
Console.WriteLine(" b1.Equals(b2) => " + (b1.Equals(b2)));
Console.WriteLine(" b1==b3 => " + (b1==b3));
Console.WriteLine(" b1.Equals(b3) => " + (b1.Equals(b3)));
Console.WriteLine(" b1==b4 => " + (b1 == b4));
Console.WriteLine(" b1.Equals(b4) => " + (b1.Equals(b4)));
Console.WriteLine(" b==d1 => " + (b == d1));
Console.WriteLine(" b.Equals(d1) => " + (b.Equals(d1)));