<PackageReference Include="NUnit" Version="3.2.1" />

EqualityAdapter

public abstract class EqualityAdapter
EqualityAdapter class handles all equality comparisons that use an IEqualityComparer, IEqualityComparer<T> or a ComparisonAdapter.
using System; using System.Collections; using System.Collections.Generic; using System.Reflection; namespace NUnit.Framework.Constraints { public abstract class EqualityAdapter { private class ComparerAdapter : EqualityAdapter { private IComparer comparer; public ComparerAdapter(IComparer comparer) { this.comparer = comparer; } public override bool AreEqual(object x, object y) { return comparer.Compare(x, y) == 0; } } private class EqualityComparerAdapter : EqualityAdapter { private IEqualityComparer comparer; public EqualityComparerAdapter(IEqualityComparer comparer) { this.comparer = comparer; } public override bool AreEqual(object x, object y) { return comparer.Equals(x, y); } } internal class PredicateEqualityAdapter<TActual, TExpected> : EqualityAdapter { private readonly Func<TActual, TExpected, bool> _comparison; public override bool CanCompare(object x, object y) { return true; } public override bool AreEqual(object x, object y) { return _comparison((TActual)y, (TExpected)x); } public PredicateEqualityAdapter(Func<TActual, TExpected, bool> comparison) { _comparison = comparison; } } private abstract class GenericEqualityAdapter<T> : EqualityAdapter { public override bool CanCompare(object x, object y) { if (IntrospectionExtensions.GetTypeInfo(typeof(T)).IsAssignableFrom(x.GetType().GetTypeInfo())) return IntrospectionExtensions.GetTypeInfo(typeof(T)).IsAssignableFrom(y.GetType().GetTypeInfo()); return false; } protected void ThrowIfNotCompatible(object x, object y) { if (!IntrospectionExtensions.GetTypeInfo(typeof(T)).IsAssignableFrom(x.GetType().GetTypeInfo())) throw new ArgumentException("Cannot compare " + x.ToString()); if (!IntrospectionExtensions.GetTypeInfo(typeof(T)).IsAssignableFrom(y.GetType().GetTypeInfo())) throw new ArgumentException("Cannot compare " + y.ToString()); } } private class EqualityComparerAdapter<T> : GenericEqualityAdapter<T> { private IEqualityComparer<T> comparer; public EqualityComparerAdapter(IEqualityComparer<T> comparer) { this.comparer = comparer; } public override bool AreEqual(object x, object y) { ThrowIfNotCompatible(x, y); return comparer.Equals((T)x, (T)y); } } private class ComparerAdapter<T> : GenericEqualityAdapter<T> { private IComparer<T> comparer; public ComparerAdapter(IComparer<T> comparer) { this.comparer = comparer; } public override bool AreEqual(object x, object y) { ThrowIfNotCompatible(x, y); return comparer.Compare((T)x, (T)y) == 0; } } private class ComparisonAdapter<T> : GenericEqualityAdapter<T> { private Comparison<T> comparer; public ComparisonAdapter(Comparison<T> comparer) { this.comparer = comparer; } public override bool AreEqual(object x, object y) { ThrowIfNotCompatible(x, y); return comparer((T)x, (T)y) == 0; } } public abstract bool AreEqual(object x, object y); public virtual bool CanCompare(object x, object y) { if (x is string && y is string) return true; if (x is IEnumerable || y is IEnumerable) return false; return true; } public static EqualityAdapter For(IComparer comparer) { return new ComparerAdapter(comparer); } public static EqualityAdapter For(IEqualityComparer comparer) { return new EqualityComparerAdapter(comparer); } public static EqualityAdapter For<TExpected, TActual>(Func<TExpected, TActual, bool> comparison) { return new PredicateEqualityAdapter<TExpected, TActual>(comparison); } public static EqualityAdapter For<T>(IEqualityComparer<T> comparer) { return new EqualityComparerAdapter<T>(comparer); } public static EqualityAdapter For<T>(IComparer<T> comparer) { return new ComparerAdapter<T>(comparer); } public static EqualityAdapter For<T>(Comparison<T> comparer) { return new ComparisonAdapter<T>(comparer); } } }