EquatablesComparer
Comparator for two types related by IEquatable<T>.
using System;
using System.Collections.Generic;
using System.Reflection;
namespace NUnit.Framework.Constraints.Comparers
{
internal class EquatablesComparer : IChainComparer
{
private readonly NUnitEqualityComparer _equalityComparer;
internal EquatablesComparer(NUnitEqualityComparer equalityComparer)
{
_equalityComparer = equalityComparer;
}
public bool? Equal(object x, object y, ref Tolerance tolerance, bool topLevelComparison = true)
{
if (_equalityComparer.CompareAsCollection & topLevelComparison)
return null;
Type type = x.GetType();
Type type2 = y.GetType();
MethodInfo methodInfo = FirstImplementsIEquatableOfSecond(type, type2);
if (methodInfo != (MethodInfo)null)
return InvokeFirstIEquatableEqualsSecond(x, y, methodInfo);
methodInfo = FirstImplementsIEquatableOfSecond(type2, type);
if (type != type2 && methodInfo != (MethodInfo)null)
return InvokeFirstIEquatableEqualsSecond(y, x, methodInfo);
return null;
}
private static MethodInfo FirstImplementsIEquatableOfSecond(Type first, Type second)
{
KeyValuePair<Type, MethodInfo> keyValuePair = default(KeyValuePair<Type, MethodInfo>);
foreach (KeyValuePair<Type, MethodInfo> equatableGenericArgument in GetEquatableGenericArguments(first)) {
if (equatableGenericArgument.Key.IsAssignableFrom(second) && (keyValuePair.Key == (Type)null || keyValuePair.Key.IsAssignableFrom(equatableGenericArgument.Key)))
keyValuePair = equatableGenericArgument;
}
return keyValuePair.Value;
}
private static IList<KeyValuePair<Type, MethodInfo>> GetEquatableGenericArguments(Type type)
{
List<KeyValuePair<Type, MethodInfo>> list = new List<KeyValuePair<Type, MethodInfo>>();
Type[] interfaces = type.GetInterfaces();
foreach (Type type2 in interfaces) {
if (type2.GetTypeInfo().IsGenericType && type2.GetGenericTypeDefinition().Equals(typeof(IEquatable<>)))
list.Add(new KeyValuePair<Type, MethodInfo>(type2.GetGenericArguments()[0], type2.GetMethod("Equals")));
}
return list;
}
private static bool InvokeFirstIEquatableEqualsSecond(object first, object second, MethodInfo equals)
{
if (!(equals != (MethodInfo)null))
return false;
return (bool)equals.Invoke(first, new object[1] {
second
});
}
}
}