C#与可忽略列表相等

C#与可忽略列表相等,c#,generics,compare,C#,Generics,Compare,我有一些具有许多简单属性的类(来自我无法控制的数据模型)——我希望能够找到对象的新版本是否与旧版本相同,但不想使用20种不同的“IsEqual”方法(我不太喜欢“IsEqual”名称,因为它不是与==”的类比)。另一个问题,在大多数情况下,我不希望它做深入的比较,但在某些情况下,我确实希望这样 我想要一些大致如下的东西: //Property could be PropertyInfo if that is necessary bool IsEqual<T>(T first, T s

我有一些具有许多简单属性的类(来自我无法控制的数据模型)——我希望能够找到对象的新版本是否与旧版本相同,但不想使用20种不同的“IsEqual”方法(我不太喜欢“IsEqual”名称,因为它不是与==”的类比)。另一个问题,在大多数情况下,我不希望它做深入的比较,但在某些情况下,我确实希望这样

我想要一些大致如下的东西:

//Property could be PropertyInfo if that is necessary
bool IsEqual<T>(T first, T second, List<Property> ignorableProperties=emptyList, bool recurse=false)
{
    //the comparison code returning if they are equal ignoring 
    //the properties in the ignorableProperties list, recursing if recurse == true
    //not sure how I'd handle the comparison of sub-objects in the recursive step.
}
//如果需要,属性可以是PropertyInfo
bool IsEqual(T first,T second,List ignorableProperties=emptyList,bool recurse=false)
{
//如果它们相等,则返回比较代码
//ignorableProperties列表中的属性,如果recurse==true则递归
//不确定在递归步骤中如何处理子对象的比较。
}

下面是我们代码库中的一些内容。它使用要比较的属性列表,而不是要忽略的属性列表。然后返回属性不匹配的列表:

public static List<PropertyInfo> CompareObjects<T>(T o1, T o2, List<PropertyInfo> props) where T : class
{
    var type = typeof(T);
    var mismatched = CompareObjects(type, o1, o2, props);
    return mismatched;
}

public static List<PropertyInfo> CompareObjects(Type t, object o1, object o2, List<PropertyInfo> props)
{
    List<PropertyInfo> mismatched = null;
    foreach (PropertyInfo prop in props)
    {
        if (prop.GetValue(o1, null) == null && prop.GetValue(o2, null) == null) ;
        else if (
            prop.GetValue(o1, null) == null || prop.GetValue(o2, null) == null ||
                !prop.GetValue(o1, null).Equals(prop.GetValue(o2, null)))
        {
            if (mismatched == null) mismatched = new List<PropertyInfo>();
            mismatched.Add(prop);
        }
    }
    return mismatched;
}
公共静态列表比较对象(to1,to2,List props),其中T:class
{
var类型=类型(T);
var不匹配=比较对象(类型、o1、o2、道具);
收益不匹配;
}
公共静态列表比较对象(类型t、对象o1、对象o2、列表道具)
{
列表不匹配=空;
foreach(PropertyInfo props in props)
{
if(prop.GetValue(o1,null)==null&&prop.GetValue(o2,null)==null);
否则如果(
prop.GetValue(o1,null)==null | | prop.GetValue(o2,null)==null||
!prop.GetValue(o1,null).等于(prop.GetValue(o2,null)))
{
if(mismatched==null)mismatched=new List();
不匹配。添加(道具);
}
}
收益不匹配;
}
如果您想要一个IsEqual方法,那么当您发现不匹配的属性时,只需返回
true
/
false


希望这有帮助

下面是我们代码库中的一些内容。它使用要比较的属性列表,而不是要忽略的属性列表。然后返回属性不匹配的列表:

public static List<PropertyInfo> CompareObjects<T>(T o1, T o2, List<PropertyInfo> props) where T : class
{
    var type = typeof(T);
    var mismatched = CompareObjects(type, o1, o2, props);
    return mismatched;
}

public static List<PropertyInfo> CompareObjects(Type t, object o1, object o2, List<PropertyInfo> props)
{
    List<PropertyInfo> mismatched = null;
    foreach (PropertyInfo prop in props)
    {
        if (prop.GetValue(o1, null) == null && prop.GetValue(o2, null) == null) ;
        else if (
            prop.GetValue(o1, null) == null || prop.GetValue(o2, null) == null ||
                !prop.GetValue(o1, null).Equals(prop.GetValue(o2, null)))
        {
            if (mismatched == null) mismatched = new List<PropertyInfo>();
            mismatched.Add(prop);
        }
    }
    return mismatched;
}
public static bool AreEqual<T>(this T first, T second, 
  bool recurse = false, params string[] propertiesToSkip)
{
  if (Equals(first, second)) return true;

  if (first == null)
    return second == null;
  else if (second == null)
    return false;

  if (propertiesToSkip == null) propertiesToSkip = new string[] { };
  var properties = from t in first.GetType().GetProperties()
                   where t.CanRead
                   select t;

  foreach (var property in properties)
  {
    if (propertiesToSkip.Contains(property.Name)) continue;

    var v1 = property.GetValue(first, null);
    var v2 = property.GetValue(second, null);

    if (recurse)
      if (!AreEqual(v1, v2, true, propertiesToSkip))
        return false;
      else
        continue;

    if (!Equals(v1, v2)) return false;
  }
  return true;
}
公共静态列表比较对象(to1,to2,List props),其中T:class
{
var类型=类型(T);
var不匹配=比较对象(类型、o1、o2、道具);
收益不匹配;
}
公共静态列表比较对象(类型t、对象o1、对象o2、列表道具)
{
列表不匹配=空;
foreach(PropertyInfo props in props)
{
if(prop.GetValue(o1,null)==null&&prop.GetValue(o2,null)==null);
否则如果(
prop.GetValue(o1,null)==null | | prop.GetValue(o2,null)==null||
!prop.GetValue(o1,null).等于(prop.GetValue(o2,null)))
{
if(mismatched==null)mismatched=new List();
不匹配。添加(道具);
}
}
收益不匹配;
}
如果您想要一个IsEqual方法,那么当您发现不匹配的属性时,只需返回
true
/
false

希望这有帮助

public static bool是相等的(这是T-first,T-second,
public static bool AreEqual<T>(this T first, T second, 
  bool recurse = false, params string[] propertiesToSkip)
{
  if (Equals(first, second)) return true;

  if (first == null)
    return second == null;
  else if (second == null)
    return false;

  if (propertiesToSkip == null) propertiesToSkip = new string[] { };
  var properties = from t in first.GetType().GetProperties()
                   where t.CanRead
                   select t;

  foreach (var property in properties)
  {
    if (propertiesToSkip.Contains(property.Name)) continue;

    var v1 = property.GetValue(first, null);
    var v2 = property.GetValue(second, null);

    if (recurse)
      if (!AreEqual(v1, v2, true, propertiesToSkip))
        return false;
      else
        continue;

    if (!Equals(v1, v2)) return false;
  }
  return true;
}
bool recurse=false,参数字符串[]属性跳过) { if(Equals(first,second))返回true; if(first==null) 返回second==null; else if(秒==null) 返回false; 如果(propertiesToSkip==null)propertiesToSkip=新字符串[]{}; var properties=first.GetType().GetProperties()中的t t.CanRead在哪里 选择t; foreach(属性中的var属性) { 如果(propertiesToSkip.Contains(property.Name))继续; var v1=property.GetValue(第一个,null); var v2=property.GetValue(第二个,null); if(递归) 如果(!AreEqual(v1、v2、true、propertiesToSkip)) 返回false; 其他的 继续; 如果(!Equals(v1,v2))返回false; } 返回true; }
公共静态布尔值相等(第一个T,第二个T,
bool recurse=false,参数字符串[]属性跳过)
{
if(Equals(first,second))返回true;
if(first==null)
返回second==null;
else if(秒==null)
返回false;
如果(propertiesToSkip==null)propertiesToSkip=新字符串[]{};
var properties=first.GetType().GetProperties()中的t
t.CanRead在哪里
选择t;
foreach(属性中的var属性)
{
如果(propertiesToSkip.Contains(property.Name))继续;
var v1=property.GetValue(第一个,null);
var v2=property.GetValue(第二个,null);
if(递归)
如果(!AreEqual(v1、v2、true、propertiesToSkip))
返回false;
其他的
继续;
如果(!Equals(v1,v2))返回false;
}
返回true;
}

以下是我们如何在Umbraco框架中实现这一点的,该框架使用了一个名为AbstractEquatableObject的基类,它是Sharp Architecture的BaseObject的一个修改版本

实现者重写
GetMembersForEqualityComparison()
,基类在
ConcurrentDictionary
中为应用程序的每种类型缓存PropertyInfo对象一次

我已经在这里粘贴了这个类,尽管它引用了框架中其他地方的LogHelper,所以您可以删除它(或者只使用我们的框架库,里面还有其他有用的东西)

如果您想要一个从表达式获取PropertyInfo的助手,为了避免到处都是神奇的字符串(例如,替换为
x=>x.MyProperty
),请查看ExpressionHelper的GetPropertyInfo方法,网址为

使用系统;
使用System.Collections.Concurrent;
使用System.Collections.Generic;
使用System.Linq;
运用系统反思;
使用Umbraco.Framework.Diagnostics;
命名空间Umbraco.Framework
{
/// 
///为实现的对象提供了用于建立特定于域的相等性的通用功能
///以及一个健壮的GetHa实现