1

I need to compare two lists, that contains objects of the same class, however not every property should be used to check for difference. Eg. the Id (primary key) property should not be used.

My example class:

class MyClass
{
    public System.Nullable<int> Id { get; set; }
    public int VMId { get; set; }
    public string Name { get; set; }
}

var oldR = new List<MyClass>();
oldR.Add(new MyClass() { Id = 1, VMId = 11, Name = "Test1" });
oldR.Add(new MyClass() { Id = 2, VMId = 22, Name = "Test2" });
oldR.Add(new MyClass() { Id = 3, VMId = 33, Name = "Test3" });
oldR.Add(new MyClass() { Id = 4, VMId = 44, Name = "Test4" });
oldR.Add(new MyClass() { Id = 5, VMId = 55, Name = "Test5" });

var newR = new List<MyClass>();
newR.Add(new MyClass() { Id = null, VMId = 22, Name = "Test2" });
newR.Add(new MyClass() { Id = null, VMId = 33, Name = "Test3" });
newR.Add(new MyClass() { Id = null, VMId = 44, Name = "Test43" });
newR.Add(new MyClass() { Id = null, VMId = 55, Name = "Test5" });
newR.Add(new MyClass() { Id = null, VMId = 66, Name = "Test6" });

What I would like to do with the above, is to match the two lists on the VMId property. Next I would like to check if the Name property has changed from oldR to newR.

Basically I would like to now, that Test1 should be removed from database, Test6 should be added, and Test4 should gets updated to Test43.

Hope it makes sence

EDIT: I should mention that my real class has +20 properties. I would like to now how to use linq to compare, without specifying them all? And maybe just exclude the Id property that I don't want to compare

How can I accomplish that?

user1281991
  • 763
  • 1
  • 12
  • 34
  • Try linq queries. That may help you to compare the objects easily – Dirty Developer Dec 07 '16 at 03:52
  • I should mention that my real class has +20 properties. I would like to now how to use linq to compare, without specifying them all? And maybe just exclude the Id property that I don't want to compare – user1281991 Dec 07 '16 at 03:53
  • I would use a left outer join to combine lists VMID. See msdn : https://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b – jdweng Dec 07 '16 at 04:12
  • http://stackoverflow.com/questions/2502395/comparing-object-properties-using-reflection try this – Dirty Developer Dec 07 '16 at 11:32

2 Answers2

3

There are a few standard ways to do this type of thing in C#.

If you have control over the class being compared, you can make it implement the IEquatable<T> interface and overload the Object.Equals method to define how instances are compared. You should also override Object.GetHashCode to make sure equality in Dictionarys and other hash collections works properly.

Example:

class MyClass : IEquatable<MyClass> {

    public string name;
    public int primaryKey;

    //IEquatable<T> implementation
    public bool Equals(MyClass other) => 
        !Equals(other, null) 
        && other.name == this.name;

    //Overriding Object methods
    public override bool Equals(object other) =>
        Equals(other as MyClass);

    public override int GetHashCode() => name.GetHashCode();
}

If you don't have control over that class, you can create a class that implements the IEqualityComparer<T> interface, which can compare instances of another class.

Example:

class MyComparer : IEqualityComaprer<MyClass> {
    public bool Equals(MyClass a, MyClass b) {
        if (Object.Equals(a, null)) return Object.Equals(b, null);
        if (Object.Equals(b, null)) return false;
        return a.name == b.name;
    }

    public int GetHashCode(MyClass obj) => obj.name.GetHashCode();
}

Many of the standard LINQ operators have overloads accepting IEqualityComparers as extra parameters for element comparison.

JamesFaix
  • 8,050
  • 9
  • 37
  • 73
  • 1
    Please prefer `IEqualityComparer<>` **always** and provide the desired comparer to the function where you need it. By overriding `Equals()` and `GetHashCode()` you change the default behavior and this can lead to unexpected behavior when you use the class in a different context. – Oliver Dec 08 '16 at 10:39
  • @Oliver makes a good point. `IEquatable` is to define the default comparison on that type. Do not use it to meet the needs of just one specific usage of that class. `IEqualityComparer` is much better for situations that need a specific non-standard comparison. – JamesFaix Dec 08 '16 at 15:52
2

Please look into this thread implement equatable

this will be important because it will allow you to do oldR[i].Equals(newR). Just use a nested foreach that checks all the objects and spits out a list of which items should be removed and which should be added (you could do this with removeList and addList). if you go the linq route, having the iequatable should be useful and the linq query should be simpler to write.

Community
  • 1
  • 1
peterpep
  • 314
  • 3
  • 11