using System;
using System.Linq;
using System.Linq.Expressions;
public class Test
{
public static Func<T,T,bool> MakeComparator<T>() {
var lhs = Expression.Parameter(typeof (T), "lhs");
var rhs = Expression.Parameter(typeof (T), "rhs");
var allPropChecks = typeof(T)
.GetProperties()
.Where(p => p.CanRead && p.GetIndexParameters().Length == 0)
.Select(p => Expression.Equal(Expression.Property(lhs, p), Expression.Property(rhs, p)))
.ToList();
Expression compare;
if (allPropChecks.Count == 0) {
return (a,b) => true; // Objects with no properties are the same
} else {
compare = allPropChecks[0];
compare = allPropChecks
.Skip(1)
.Aggregate(compare, Expression.AndAlso);
}
return (Func<T, T, bool>)Expression.Lambda(compare, new[] { lhs, rhs }).Compile();
}
class Point3D {
public int X { get; set; }
public int Y { get; set; }
public int Z { get; set; }
}
public static void Main() {
var cmp = MakeComparator<Point3D>();
var p1 = new Point3D {X = 1, Y = 2, Z = 3};
var p2 = new Point3D { X = 1, Y = 2, Z = 3 };
var p3 = new Point3D { X = 1, Y = 3, Z = 1 };
Console.WriteLine(cmp(p1, p2));
Console.WriteLine(cmp(p2, p3));
}
}
dXNpbmcgU3lzdGVtOwp1c2luZyBTeXN0ZW0uTGlucTsKdXNpbmcgU3lzdGVtLkxpbnEuRXhwcmVzc2lvbnM7CgpwdWJsaWMgY2xhc3MgVGVzdAp7CiAgICAKICAgICAgICAgICAgcHVibGljIHN0YXRpYyBGdW5jPFQsVCxib29sPiBNYWtlQ29tcGFyYXRvcjxUPigpIHsKICAgICAgICAgICAgdmFyIGxocyA9IEV4cHJlc3Npb24uUGFyYW1ldGVyKHR5cGVvZiAoVCksICJsaHMiKTsKICAgICAgICAgICAgdmFyIHJocyA9IEV4cHJlc3Npb24uUGFyYW1ldGVyKHR5cGVvZiAoVCksICJyaHMiKTsKICAgICAgICAgICAgdmFyIGFsbFByb3BDaGVja3MgPSB0eXBlb2YoVCkKICAgICAgICAgICAgICAgIC5HZXRQcm9wZXJ0aWVzKCkKICAgICAgICAgICAgICAgIC5XaGVyZShwID0+IHAuQ2FuUmVhZCAmJiBwLkdldEluZGV4UGFyYW1ldGVycygpLkxlbmd0aCA9PSAwKQogICAgICAgICAgICAgICAgLlNlbGVjdChwID0+IEV4cHJlc3Npb24uRXF1YWwoRXhwcmVzc2lvbi5Qcm9wZXJ0eShsaHMsIHApLCBFeHByZXNzaW9uLlByb3BlcnR5KHJocywgcCkpKQogICAgICAgICAgICAgICAgLlRvTGlzdCgpOwogICAgICAgICAgICBFeHByZXNzaW9uIGNvbXBhcmU7CiAgICAgICAgICAgIGlmIChhbGxQcm9wQ2hlY2tzLkNvdW50ID09IDApIHsKICAgICAgICAgICAgICAgIHJldHVybiAoYSxiKSA9PiB0cnVlOyAvLyBPYmplY3RzIHdpdGggbm8gcHJvcGVydGllcyBhcmUgdGhlIHNhbWUKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIGNvbXBhcmUgPSBhbGxQcm9wQ2hlY2tzWzBdOwogICAgICAgICAgICAgICAgY29tcGFyZSA9IGFsbFByb3BDaGVja3MKICAgICAgICAgICAgICAgICAgICAuU2tpcCgxKQogICAgICAgICAgICAgICAgICAgIC5BZ2dyZWdhdGUoY29tcGFyZSwgRXhwcmVzc2lvbi5BbmRBbHNvKTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gKEZ1bmM8VCwgVCwgYm9vbD4pRXhwcmVzc2lvbi5MYW1iZGEoY29tcGFyZSwgbmV3W10geyBsaHMsIHJocyB9KS5Db21waWxlKCk7CiAgICAgICAgfQogICAgICAgY2xhc3MgUG9pbnQzRCB7CiAgICAgICAgICAgIHB1YmxpYyBpbnQgWCB7IGdldDsgc2V0OyB9CiAgICAgICAgICAgIHB1YmxpYyBpbnQgWSB7IGdldDsgc2V0OyB9CiAgICAgICAgICAgIHB1YmxpYyBpbnQgWiB7IGdldDsgc2V0OyB9CiAgICAgICAgfQogICAgICAgIHB1YmxpYyBzdGF0aWMgdm9pZCBNYWluKCkgewogICAgICAgICAgICB2YXIgY21wID0gTWFrZUNvbXBhcmF0b3I8UG9pbnQzRD4oKTsKICAgICAgICAgICAgdmFyIHAxID0gbmV3IFBvaW50M0Qge1ggPSAxLCBZID0gMiwgWiA9IDN9OwogICAgICAgICAgICB2YXIgcDIgPSBuZXcgUG9pbnQzRCB7IFggPSAxLCBZID0gMiwgWiA9IDMgfTsKICAgICAgICAgICAgdmFyIHAzID0gbmV3IFBvaW50M0QgeyBYID0gMSwgWSA9IDMsIFogPSAxIH07CiAgICAgICAgICAgIENvbnNvbGUuV3JpdGVMaW5lKGNtcChwMSwgcDIpKTsKICAgICAgICAgICAgQ29uc29sZS5Xcml0ZUxpbmUoY21wKHAyLCBwMykpOwogICAgICAgIH0KfQ==