如何检查对象内容相等性而不是对象引用相等性

本文关键字:对象引用 何检查 检查 对象 | 更新日期: 2023-09-27 18:32:53

我有一个实体框架实体,看起来像这样:

class ListItemEtlObject
{
    public int ID { get; set; }
    public string ProjectName { get; set; }
    public string ProjectType { get; set; }
    public string ProjectCode { get; set; }
    public string ProjectDescription { get; set; }
    public string JobNo { get; set; }
    public string JobDescription { get; set; }
    public bool Include { get; set; }
}

我正在将两个不同数据源中的项目提取到 IEnumerable 列表中。如何在不使用一堆 if 语句来检查属性值之间是否存在差异的情况下比较项目,然后在它们不匹配时设置属性的值?这个想法是保持列表同步。此外,列表 A 设置了 ID 值,列表 B 没有。我只是觉得有比一堆更好的方法可以做到这一点

if(objectA.ProjectName != objectB.ProjectName)
{
   objectA.ProjectName = objectB.ProjectName;
}

如何检查对象内容相等性而不是对象引用相等性

如果您可以控制源对象,那么支持基于值的相等的最佳声明性方法是实现IEquatable<T>。 不幸的是,这确实需要您枚举所有这些检查,但它在实际对象定义位置完成一次,不需要在整个代码库中重复。

class ListItemEtlObject : IEquatable<ListITemEtlObject>
{
  ...
  public void Equals(ListITemEtlObject other) {
    if (other == null) {
      return false;
    }
    return 
      ID == other.ID &&
      ProjectName == other.ProjectName &&
      ProjectType == other.ProjectType &&
      ... ;
  }
}

此外,您可以选择在对象类型上重载相等运算符,并允许使用者简单地在ListItemEtlObject实例上使用!===,并获得值相等而不是引用相等。

public static bool operator==(ListItemEtlObject left, ListItemEtlObject right) {
  return EqualityComparer<ListItemEtlObject>.Default.Equals(left, right);
}
public static bool operator!=(ListItemEtlObject left, ListItemEtlObject right) {
  return !(left == right);
}

最简单的方法是在你的类上提供一个计算特定哈希的方法,就像GetHashCode一样,然后如果两个实例计算相同的哈希,它们可以说是等效的。

您可以使用

反射来简化它 =)

    public virtual void SetDifferences(MyBaseClass compareTo)
    {
        var differences = this.GetDifferentProperties(compareTo);
        differences.ToList().ForEach(x =>
        {
            x.SetValue(this, x.GetValue(compareTo, null), null);
        });
    }
    public virtual IEnumerable<PropertyInfo> GetDifferentProperties(MyBaseClass compareTo)
    {
        var signatureProperties = this.GetType().GetProperties();
        return (from property in signatureProperties
                let valueOfThisObject = property.GetValue(this, null)
                let valueToCompareTo = property.GetValue(compareTo, null)
                where valueOfThisObject != null || valueToCompareTo != null
                where (valueOfThisObject == null ^ valueToCompareTo == null) || (!valueOfThisObject.Equals(valueToCompareTo))
                select property);
    }

这是我为你做的几个测试

    [TestMethod]
    public void CheckDifferences()
    {
        var f = new OverridingGetHashCode();
        var g = new OverridingGetHashCode();
        f.GetDifferentProperties(g).Should().NotBeNull().And.BeEmpty();
        f.Include = true;
        f.GetDifferentProperties(g).Should().NotBeNull().And.HaveCount(1).And.Contain(f.GetType().GetProperty("Include"));
        g.Include = true;
        f.GetDifferentProperties(g).Should().NotBeNull().And.BeEmpty();
        g.JobDescription = "my job";
        f.GetDifferentProperties(g).Should().NotBeNull().And.HaveCount(1).And.Contain(f.GetType().GetProperty("JobDescription"));
    }
    [TestMethod]
    public void SetDifferences()
    {
        var f = new OverridingGetHashCode();
        var g = new OverridingGetHashCode();
        g.Include = true;
        f.SetDifferences(g);
        f.GetDifferentProperties(g).Should().NotBeNull().And.BeEmpty();
        f.Include = true;
        g.Include = false;
        f.SetDifferences(g);
        f.GetDifferentProperties(g).Should().NotBeNull().And.BeEmpty();
        f.Include.Should().BeFalse();
    }