using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
namespace Digitigrade {
///
/// The default EqualityComparer instance can be grossly inefficient as it requires the use of reflection
/// during each comparison. This allows classes to specify their own, yielding a constant factor of ~100
/// performance increase if the comparer is used repeatedly. This is especially useful if the default equality
/// comparer has to chain the use of other default equality comparers.
/// Just use PreparedEqualityComparer.Default instead of EqualityComparer.Default.
/// This gracefully degrades to the standard behavior.
///
public static class PreparedEqualityComparer {
public static IEqualityComparer Default {
get {
Type valueType = typeof(T);
foreach (Type proxy in valueType.GetCustomAttributes(typeof(PreparedEqualityComparerTypeProxyAttribute), true).Cast().Select(c => c.EqualityComparerType)) {
Type specializedComparer = proxy.ContainsGenericParameters
? proxy.MakeGenericType(valueType.GetGenericArguments())
: proxy;
if (!specializedComparer.IsClass && !specializedComparer.IsValueType)
throw new ArgumentException("prepared equality comparer is not a class");
if (!specializedComparer.IsSubclassOf(typeof(IEqualityComparer)))
continue;
ConstructorInfo constructor = specializedComparer.GetConstructor(new Type[] { });
if (constructor == null)
continue;
return (IEqualityComparer)constructor.Invoke(new object[] { });
}
return EqualityComparer.Default;
}
}
}
}