user1281991
user1281991

Reputation: 773

C# get differences in two matching lists

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?

Upvotes: 1

Views: 141

Answers (2)

JamesFaix
JamesFaix

Reputation: 8655

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.

Upvotes: 3

peterpep
peterpep

Reputation: 324

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.

Upvotes: 2

Related Questions