已关闭 。这个问题是基于观点的。它当前不接受答案。
2年前关闭。
已锁定 。该问题及其答案被锁定,因为该问题是题外话,但具有历史意义。它目前不接受新的答案或互动。
这是我作为许多其他类继承的类的方法提出的。这个想法是它允许在相同类型的对象的属性之间进行简单的比较。
现在,这确实可行-但为了提高代码质量,我认为应该将其进行仔细检查。如何更好/更高效/等等?
/// <summary> /// Compare property values (as strings) /// </summary> /// <param name="obj"></param> /// <returns></returns> public bool PropertiesEqual(object comparisonObject) { Type sourceType = this.GetType(); Type destinationType = comparisonObject.GetType(); if (sourceType == destinationType) { PropertyInfo[] sourceProperties = sourceType.GetProperties(); foreach (PropertyInfo pi in sourceProperties) { if ((sourceType.GetProperty(pi.Name).GetValue(this, null) == null && destinationType.GetProperty(pi.Name).GetValue(comparisonObject, null) == null)) { // if both are null, don't try to compare (throws exception) } else if (!(sourceType.GetProperty(pi.Name).GetValue(this, null).ToString() == destinationType.GetProperty(pi.Name).GetValue(comparisonObject, null).ToString())) { // only need one property to be different to fail Equals. return false; } } } else { throw new ArgumentException("Comparison object must be of the same type.","comparisonObject"); } return true; }
我一直在寻找一段代码,这些代码可以做类似的事情来帮助编写单元测试。这是我最终使用的内容。
public static bool PublicInstancePropertiesEqual<T>(T self, T to, params string[] ignore) where T : class { if (self != null && to != null) { Type type = typeof(T); List<string> ignoreList = new List<string>(ignore); foreach (System.Reflection.PropertyInfo pi in type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)) { if (!ignoreList.Contains(pi.Name)) { object selfValue = type.GetProperty(pi.Name).GetValue(self, null); object toValue = type.GetProperty(pi.Name).GetValue(to, null); if (selfValue != toValue && (selfValue == null || !selfValue.Equals(toValue))) { return false; } } } return true; } return self == to; }
编辑:
与上面相同的代码,但使用LINQ和Extension方法:
public static bool PublicInstancePropertiesEqual<T>(this T self, T to, params string[] ignore) where T : class { if (self != null && to != null) { var type = typeof(T); var ignoreList = new List<string>(ignore); var unequalProperties = from pi in type.GetProperties(BindingFlags.Public | BindingFlags.Instance) where !ignoreList.Contains(pi.Name) && pi.GetUnderlyingType().IsSimpleType() && pi.GetIndexParameters().Length == 0 let selfValue = type.GetProperty(pi.Name).GetValue(self, null) let toValue = type.GetProperty(pi.Name).GetValue(to, null) where selfValue != toValue && (selfValue == null || !selfValue.Equals(toValue)) select selfValue; return !unequalProperties.Any(); } return self == to; } public static class TypeExtensions { /// <summary> /// Determine whether a type is simple (String, Decimal, DateTime, etc) /// or complex (i.e. custom class with public properties and methods). /// </summary> /// <see cref="http://stackoverflow.com/questions/2442534/how-to-test-if-type-is-primitive"/> public static bool IsSimpleType( this Type type) { return type.IsValueType || type.IsPrimitive || new[] { typeof(String), typeof(Decimal), typeof(DateTime), typeof(DateTimeOffset), typeof(TimeSpan), typeof(Guid) }.Contains(type) || (Convert.GetTypeCode(type) != TypeCode.Object); } public static Type GetUnderlyingType(this MemberInfo member) { switch (member.MemberType) { case MemberTypes.Event: return ((EventInfo)member).EventHandlerType; case MemberTypes.Field: return ((FieldInfo)member).FieldType; case MemberTypes.Method: return ((MethodInfo)member).ReturnType; case MemberTypes.Property: return ((PropertyInfo)member).PropertyType; default: throw new ArgumentException ( "Input MemberInfo must be if type EventInfo, FieldInfo, MethodInfo, or PropertyInfo" ); } } }