ILLightenComparer is a flexible library that can generate very effective and comprehensive IComparer<T>
and IEqualityComparer<T>
implementations on runtime using advantages of IL
code emission.
IEnumerable<T>
, T[]
, T[][]
).var comparer = ComparerBuilder.Default.GetComparer<Tuple<int, string>>();
var compareResult = comparer.Compare(x, y);
var equalityComparer = ComparerBuilder.Default.GetEqualityComparer<Tuple<int, string>>();
var equalityResult = equalityComparer.Equals(x, y);
var hashResult = equalityComparer.GetHashCode(x);
And it “just works”, no need complex configuration.
var x = new[] { 1, 2, 3 };
var y = new[] { 2, 3, 1 };
var comparer = new ComparerBuilder()
.For<int[]>(c => c.IgnoreCollectionsOrder(true))
.GetComparer();
var result = comparer.Compare(x, y);
result.Should().Be(0);
var x = new Tuple<int, string, double>(1, "value 1", 1.1);
var y = new Tuple<int, string, double>(1, "value 2", 2.2);
var comparer = new ComparerBuilder()
.For<Tuple<int, string, double>>()
.Configure(c => c.IgnoreMember(o => o.Item2)
.IgnoreMember(o => o.Item3))
.GetComparer();
var result = comparer.Compare(x, y);
result.Should().Be(0);
var x = _fixture.Create<Tuple<int, string>>();
var y = _fixture.Create<Tuple<int, string>>();
var customComparer = new CustomizableComparer<Tuple<int, string>>((a, b) => 0); // makes all objects always equal
var comparer = new ComparerBuilder()
.Configure(c => c.SetCustomComparer(customComparer))
.GetComparer<Tuple<int, string>>();
var result = comparer.Compare(x, y);
result.Should().Be(0);
var builder = new ComparerBuilder(c => c.SetDefaultCyclesDetection(false)); // defines initial configuration
// adds some configuration later
builder.Configure(c => c
.SetStringComparisonType(
typeof(Tuple<int, string, Tuple<short, string>>),
StringComparison.InvariantCultureIgnoreCase)
.IgnoreMember<Tuple<int, string, Tuple<short, string>>, int>(o => o.Item1));
// defines configuration for specific types
builder.For<Tuple<short, string>>(c => c.DefineMembersOrder(
order => order.Member(o => o.Item2)
.Member(o => o.Item2)));
// adds additional configuration to existing configuration
builder.For<Tuple<int, string, Tuple<short, string>>>(c => c.IncludeFields(false));
var x = new Tuple<int, string>(1, "text");
var y = new Tuple<int, string>(2, "TEXT");
// initially configuration defines case insensitive string comparison
var builder = new ComparerBuilder()
.For<Tuple<int, string>>(c => c
.SetStringComparisonType(StringComparison.CurrentCultureIgnoreCase)
.DetectCycles(false));
// in addition, setup to ignore first member
builder.Configure(c => c.IgnoreMember(o => o.Item1));
// this version takes in account only case insensitive second member
var ignoreCaseComparer = builder.GetComparer();
// override string comparison type with case sensitive setting and build new comparer
var originalCaseComparer = builder
.For<Tuple<int, string>>()
.Configure(c => c.SetStringComparisonType(StringComparison.Ordinal))
.GetComparer();
// first comparer ignores case for strings still
ignoreCaseComparer.Compare(x, y).Should().Be(0);
// second comparer still ignores first member but uses new string comparison type
var result = originalCaseComparer.Compare(x, y);
result.Should().Be(string.Compare("text", "TEXT", StringComparison.Ordinal));
sealed
classes and small types (sbyte
, byte
, char
, short
, ushort
) when possible.IComparable<T>
interface then this implementations will be used.In case of an unexpected behavior, please welcome to create an issue and provide the type and data that you use.