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

C# 创建用于比较自身实例的类的最佳方法,c#,.net,oop,compare,data-annotations,C#,.net,Oop,Compare,Data Annotations,我正在编写一个程序,从数据库中获取数据,并将其逐值与旧数据进行比较,然后需要能够: 输出旧数据 输出新数据 仅输出差异 因此,为了简单起见,假设我创建了以下类来存储这些值: class MyClass { // These fields will not be compared: public string Id { get; set; } public string Name { get; set; } public string NONCompField1 {

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

  • 输出旧数据
  • 输出新数据
  • 仅输出差异
  • 因此,为了简单起见,假设我创建了以下类来存储这些值:

    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;
        }
    
    public IEnumerable getDiff(MyClass其他)
    {
    var RetVal=新列表();
    如果(CompField1!=其他.CompField1)
    RetVal.Add(Tuple.Create(“CompField1”,CompField1,Other.CompField1));
    如果(CompField2!=其他.CompField2)
    添加(Tuple.Create(“CompField2”,CompField2.ToString(),Other.CompField2.ToString());
    如果(CompField3!=其他.CompField3)
    添加(Tuple.Create(“CompField3”,CompField3.ToString(),Other.CompField3.ToString());
    如果(CompField4!=其他.CompField4)
    添加(Tuple.Create(“CompField4”,CompField4.ToString(),Other.CompField4.ToString());
    返回返回;
    }
    
    这给了我一个
    元组(
    Field\u Name
    Current\u Value
    Old\u Value
    ),效果很好,但我正在寻找一种更好的、模式动态的方法来实现这一点,它将允许将来添加新的字段-无论它们是
    CompareFields
    (需要更新
    getdiff
    )或
    nonmpfields
    (无需更新
    getdiff

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

    是否有更好/更成熟的方法来实现这一点,从而最大限度地减少更新额外代码的需要


    谢谢!!!

    创建一个代理列表,将项目投影到要比较的每个不同属性,然后比较两个项目上每个投影的结果:

    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());
    }
    
    public IEnumerable getDiff(MyClass其他)
    {
    var比较=新[]
    {
    Tuple.Create(“CompField1”,item=>item.CompField1),
    Tuple.Create(“CompField2”,item=>item.CompField2),
    Tuple.Create(“CompField3”,item=>item.CompField3),
    Tuple.Create(“CompField4”,item=>item.CompField4),
    };
    比较中的比较返回
    让myValue=comparison.Item2(此)
    让otherValue=comparison.Item2(其他)
    其中!object.Equals(myValue,otherValue)
    选择Tuple.Create(comparison.Item1,
    myValue.ToString(),
    otherValue.ToString());
    }
    
    仅供参考-对于其他希望与我在这里所做相同操作的人,我最终修改了我找到的代码

    这允许我做的是传入一个用于比较的属性名列表(尽管示例的作用正好相反——它有一个可以忽略的名称列表,但这是一个简单的更改),否则修改非常简单


    希望这有助于至少在相同的情况下指导其他人。

    如果你不介意使用第三方工具,那么请多谢,YuvalItzchakov。我尽量避免使用外部的库,但这绝对是一件好事。谢谢!Servy,非常感谢。但是看起来这里仍然有需要。每次我添加一个新的(可比较的)属性时更新
    getdiff
    方法。有什么原因比使用某种形式的DataAnnotation/Reflection(这只意味着在创建时装饰属性)更好吗?:)-真的,只是想知道你这样做是否有原因?如果出于某种原因这更好(我仍然是一个不折不扣的人,如果可能的话,我有兴趣学习最佳实践)