0

I am writing a program that gets data from a database and compares it value-by-value to older data and then needs to be able to:

  1. Output the Old Data
  2. Output the New Data
  3. Output only the Differences

So, for simplicity's sake, suppose I created the following class to store the values:

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; }
}

And, as the name suggests in my example, I want to compare the old and new values but only based upon the CompFields to find the differences.

I know I can hard-code a solution as follows:

    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;
    }

And that gives me back a Tuple<string, string, string> of (Field_Name, Current_Value, Old_Value) and that works just fine, but I'm looking for a nicer, mode dynamic way to do this that will allow for new fields being added in the future - whether they be CompareFields (need to update the GetDiffs) or NONCompFields (no need to update the GetDiffs).

My first thought would be to use DataAnnotations and then reflection to find fields with a specific attribute and loop through them for the GetDiffs method, but that seems like a cheat / bad way to do things.

Is there a better / more established way to do this that would minimize the need to update extra code?

Thanks!!!

John Bustos
  • 19,036
  • 17
  • 89
  • 151
  • 1
    If you don't mind using Third Party tools, consider [this](http://comparenetobjects.codeplex.com) – Yuval Itzchakov Dec 01 '15 at 17:48
  • Thanks so much, @YuvalItzchakov. I'm trying to avoid using an external library if possible, but it is definitely a good thing to know about! Thanks! – John Bustos Dec 01 '15 at 17:58

2 Answers2

1

Create a list of delegates that projects the item out to each of the different properties you want to compare, and then compare the results of each of those projections on the two items:

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());
}
Servy
  • 202,030
  • 26
  • 332
  • 449
  • Servy, thank you so much. But it seems like here there is still the need to update the `GetDiffs` method each time I add a new (comparable) property. Is there a reason why this way is better than using some form of DataAnnotation / Reflection (that would just mean decorating the property at the time of creation)? – John Bustos Dec 01 '15 at 17:58
  • :) - Truly, just wondering if there was a reason for your way over that? If this is better for some reason (I'm still very much a noob and interested in learning the best practices if at all possible) – John Bustos Dec 01 '15 at 18:05
1

FYI - For anyone else who's looking to do the same as what I've done here, I ended up modifying the code I found here.

What this allowed me to do was to pass in a list of property names to use for comparing (although the example does the opposite - It has a list of names to ignore, but that's an easy change) and the modifications were pretty simple otherwise.

Hope this helps at least direct others in the same kind of situation.

Community
  • 1
  • 1
John Bustos
  • 19,036
  • 17
  • 89
  • 151