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

EquatablesComparer

static class EquatablesComparer
Comparator for two types related by IEquatable<T>.
using NUnit.Framework.Internal; using System; using System.Reflection; using System.Runtime.CompilerServices; namespace NUnit.Framework.Constraints.Comparers { [NullableContext(1)] [Nullable(0)] internal static class EquatablesComparer { [Nullable(0)] private readonly struct EquatableMethodImpl { public MethodInfo Method { get; } public Type Argument { get; } public EquatableMethodImpl(MethodInfo method, Type arg) { Method = method; Argument = arg; } } public static EqualMethodResult Equal(object x, object y, ref Tolerance tolerance, ComparisonState state, NUnitEqualityComparer equalityComparer) { if (equalityComparer.CompareAsCollection && state.TopLevelComparison) return EqualMethodResult.TypesNotSupported; Type type = x.GetType(); Type type2 = y.GetType(); if (equalityComparer.CompareProperties && type.HasCompilerGeneratedEquals()) return EqualMethodResult.TypesNotSupported; MethodInfo methodInfo = FirstImplementsIEquatableOfSecond(type, type2); if ((object)methodInfo != null) { if (tolerance.HasVariance) return EqualMethodResult.ToleranceNotSupported; if (!InvokeFirstIEquatableEqualsSecond(x, y, methodInfo)) return EqualMethodResult.ComparedNotEqual; return EqualMethodResult.ComparedEqual; } methodInfo = FirstImplementsIEquatableOfSecond(type2, type); if (type != type2 && (object)methodInfo != null) { if (tolerance.HasVariance) return EqualMethodResult.ToleranceNotSupported; if (!InvokeFirstIEquatableEqualsSecond(y, x, methodInfo)) return EqualMethodResult.ComparedNotEqual; return EqualMethodResult.ComparedEqual; } return EqualMethodResult.TypesNotSupported; } [return: Nullable(2)] private static MethodInfo FirstImplementsIEquatableOfSecond(Type first, Type second) { EquatableMethodImpl equatableMethodImpl = default(EquatableMethodImpl); EquatableMethodImpl[] equatableImplementations = GetEquatableImplementations(first); for (int i = 0; i < equatableImplementations.Length; i++) { EquatableMethodImpl equatableMethodImpl2 = equatableImplementations[i]; if (equatableMethodImpl2.Argument.IsAssignableFrom(second) && ((object)equatableMethodImpl.Argument == null || equatableMethodImpl.Argument.IsAssignableFrom(equatableMethodImpl2.Argument))) equatableMethodImpl = equatableMethodImpl2; } return equatableMethodImpl.Method; } private static EquatableMethodImpl[] GetEquatableImplementations(Type type) { Type[] array = type.FindInterfaces((Type t, object _) => <GetEquatableImplementations>g__IsIEquatableOfT|2_0(t), string.Empty); EquatableMethodImpl[] array2 = new EquatableMethodImpl[array.Length]; for (int i = 0; i < array.Length; i++) { InterfaceMapping interfaceMap = type.GetInterfaceMap(array[i]); MethodInfo methodInfo = interfaceMap.TargetMethods[0]; array2[i] = new EquatableMethodImpl(methodInfo, methodInfo.GetParameters()[0].ParameterType); } return array2; } private static bool InvokeFirstIEquatableEqualsSecond(object first, object second, MethodInfo equals) { return (bool)equals.Invoke(first, new object[1] { second }); } } }