进行一些反思,也许是
expression.Compile()为了表现?(请注意,这里的静态ctor确保我们每次仅编译一次
T):
using System;using System.Linq.expressions;public class Report { public int Id { get; set; } public int ProjectId { get; set; } static void Main() { Report a = new Report { Id = 1, ProjectId = 13 }, b = new Report { Id = 1, ProjectId = 13 }, c = new Report { Id = 1, ProjectId = 12 }; Console.WriteLine(PropertyCompare.Equal(a, b)); Console.WriteLine(PropertyCompare.Equal(a, c)); }}static class PropertyCompare { public static bool Equal<T>(T x, T y) { return Cache<T>.Compare(x, y); } static class Cache<T> { internal static readonly Func<T, T, bool> Compare; static Cache() { var props = typeof(T).GetProperties(); if (props.Length == 0) { Compare = delegate { return true; }; return; } var x = expression.Parameter(typeof(T), "x"); var y = expression.Parameter(typeof(T), "y"); expression body = null; for (int i = 0; i < props.Length; i++) { var propEqual = expression.Equal( expression.Property(x, props[i]), expression.Property(y, props[i])); if (body == null) { body = propEqual; } else { body = expression.AndAlso(body, propEqual); } } Compare = expression.Lambda<Func<T, T, bool>>(body, x, y) .Compile(); } }}编辑:更新为也处理字段:
static class MemberCompare{ public static bool Equal<T>(T x, T y) { return Cache<T>.Compare(x, y); } static class Cache<T> { internal static readonly Func<T, T, bool> Compare; static Cache() { var members = typeof(T).GetProperties( BindingFlags.Instance | BindingFlags.Public) .Cast<MemberInfo>().Concat(typeof(T).GetFields( BindingFlags.Instance | BindingFlags.Public) .Cast<MemberInfo>()); var x = expression.Parameter(typeof(T), "x"); var y = expression.Parameter(typeof(T), "y"); expression body = null; foreach(var member in members) { expression memberEqual; switch (member.MemberType) { case MemberTypes.Field: memberEqual = expression.Equal( expression.Field(x, (FieldInfo)member), expression.Field(y, (FieldInfo)member)); break; case MemberTypes.Property: memberEqual = expression.Equal( expression.Property(x, (PropertyInfo)member), expression.Property(y, (PropertyInfo)member)); break; default: throw new NotSupportedException( member.MemberType.ToString()); } if (body == null) { body = memberEqual; } else { body = expression.AndAlso(body, memberEqual); } } if (body == null) { Compare = delegate { return true; }; } else { Compare = expression.Lambda<Func<T, T, bool>>(body, x, y) .Compile(); } } }}


