创建用于比较自身实例的类的最佳方法

时间:2015-12-01 17:40:15

标签: c# .net oop compare data-annotations

我正在编写一个程序,从数据库中获取数据并将其逐个值与旧数据进行比较,然后需要能够:

  1. 输出旧数据
  2. 输出新数据
  3. 仅输出差异
  4. 因此,为简单起见,假设我创建了以下类来存储值:

    class MyClass
    {
        // These fields will not be compared:
        public string Id { get; set; }
        public string Name { get; set; }
        public string NONCompField1 { get; set; }
        public int NONCompField2 { get; set; }
    
        // These fields WILL be compared:
        public string CompField1 { get; set; }
        public int CompField2 { get; set; }
        public int CompField3 { get; set; }
        public double CompField4 { get; set; }
    }
    

    而且,正如我的例子中的名称所示,我想比较旧值和新值,但仅基于CompFields来找出差异。

    我知道我可以按如下方式对解决方案进行硬编码:

        public IEnumerable<Tuple<string, string, string>> GetDiffs(MyClass Other)
        {
            var RetVal = new List<Tuple<string, string, string>>();
    
            if (CompField1 != Other.CompField1)
                RetVal.Add(Tuple.Create("CompField1", CompField1, Other.CompField1));
            if (CompField2 != Other.CompField2)
                RetVal.Add(Tuple.Create("CompField2", CompField2.ToString(), Other.CompField2.ToString()));
            if (CompField3 != Other.CompField3)
                RetVal.Add(Tuple.Create("CompField3", CompField3.ToString(), Other.CompField3.ToString()));
            if (CompField4 != Other.CompField4)
                RetVal.Add(Tuple.Create("CompField4", CompField4.ToString(), Other.CompField4.ToString()));
    
            return RetVal;
        }
    

    这让我回到Tuple<string, string, string>Field_NameCurrent_ValueOld_Value)并且工作正常,但我正在寻找更好的,模式动态的方式,允许将来添加新字段 - 无论是CompareFields(需要更新GetDiffs)还是NONCompFields(无需更新GetDiffs)。

    我的第一个想法是使用DataAnnotations然后使用反射来查找具有特定属性的字段并循环使用GetDiffs方法,但这似乎是一种欺骗/糟糕的做事方式

    是否有更好/更成熟的方法来最大限度地减少更新额外代码的需要?

    感谢!!!

2 个答案:

答案 0 :(得分:1)

创建一个委托列表,将项目投射到您要比较的每个不同属性,然后比较这两个项目的每个投影的结果:

public IEnumerable<Tuple<string, string, string>> GetDiffs(MyClass Other)
{
    var comparisons = new[] 
    {
        Tuple.Create<string, Func<MyClass, object>>("CompField1", item => item.CompField1),
        Tuple.Create<string, Func<MyClass, object>>("CompField2", item => item.CompField2),
        Tuple.Create<string, Func<MyClass, object>>("CompField3", item => item.CompField3),
        Tuple.Create<string, Func<MyClass, object>>("CompField4", item => item.CompField4),
    };

    return from comparison in comparisons
            let myValue = comparison.Item2(this)
            let otherValue = comparison.Item2(Other)
            where !object.Equals(myValue, otherValue)
            select Tuple.Create(comparison.Item1,
                myValue.ToString(),
                otherValue.ToString());
}

答案 1 :(得分:1)

仅供参考 - 对于那些希望与我在此处所做的相同的人,我最终修改了我找到的代码here

这允许我做的是传入一个属性名称列表以用于比较(虽然示例正好相反 - 它有一个要忽略的名称列表,但这很容易改变)并且修改很漂亮很简单。

希望这有助于至少引导其他人处于相同的情况。