0

This is my model:

public class EventModel
{
    public DateTime? EVENT_DATE { get; set; }
    public decimal? EVENT_TYPE { get; set; }
    public string EVENT_DESCRIPTION { get; set; }
}

I fill this class into ObservableCollection<EventModel>. When I do that, I also deep-copy same collection. Then I want to compare these two collections in later use.

I would preferably use LINQ to do that, with something like

bool are_same = collection1.OrderBy(i => i).SequenceEqual(
                 collection2.OrderBy(i => i));

This means that both collections needs to be sorted and then compared to each other for finding differencies in ALL PROPERTIES.

There are a lot of examples for implementing IComparable & IEqualityComparer, but I'm confused about what I need and how.

I would appreciate If someone would show me how this can be done in C#.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Lucy82
  • 654
  • 2
  • 12
  • 32
  • 1
    Show what exactly? Find differences? How to implement IComparable/IEqualityComparer? Does order matter when comparing collections? What should the output be? Can you give an example of input/expected output? What is the end goal here? – JonasH May 31 '21 at 11:03
  • @JonasH, `collection1` is the collection which is bound to UI. `collection2` is used for enabling button for saving changes to database. So output should be a `boolean` indicating whether any propery in collection has changed. Items are allways in same position (I think), I deep-copy `collection1` right after I get data from database. – Lucy82 May 31 '21 at 11:08

1 Answers1

1

If you simply want to check if the two collections are equal you need to define what equality is, for example by implementing IEqualityComparer<T>. This can also be done by implementing IEquatable<T> or or by overriding Equals(object) and GetHasCode. This can be done automatically by some refactoring tools:

public sealed class EventModelEqualityComparer : IEqualityComparer<EventModel>
    {
        public bool Equals(EventModel x, EventModel y)
        {
            if (ReferenceEquals(x, y)) return true;
            if (ReferenceEquals(x, null)) return false;
            if (ReferenceEquals(y, null)) return false;
            if (x.GetType() != y.GetType()) return false;
            return Nullable.Equals(x.EVENT_DATE, y.EVENT_DATE) &&
                   x.EVENT_TYPE == y.EVENT_TYPE &&
                   x.EVENT_DESCRIPTION == y.EVENT_DESCRIPTION;
        }

        public int GetHashCode(EventModel obj)
        {
            unchecked
            {
                var hashCode = obj.EVENT_DATE.GetHashCode();
                hashCode = (hashCode * 397) ^ obj.EVENT_TYPE.GetHashCode();
                hashCode = (hashCode * 397) ^ (obj.EVENT_DESCRIPTION != null ? obj.EVENT_DESCRIPTION.GetHashCode() : 0);
                return hashCode;
            }
        }
    }

To compare two collections to see if they contains the same items, but in arbitrary positions, you can use a HashSet.SetEquals:

myCollection.ToHashSet(new EventModelEqualityComparer()).SetEquals(myOtherCollection);
JonasH
  • 28,608
  • 2
  • 10
  • 23
  • If I understand you correctly, this class is completely independent. I should not implement IEqualityCompared directly in EventModel ? Next, how can this be done automatically, you mentioned refactoring tools ? And finally, wil this return boolean If changes were made ? – Lucy82 May 31 '21 at 11:37
  • the implementation of `IEqualityComparer` is a independent class, but may be implemented as a nested class if you want. You can let `EventModel` implement `IEquatable`, this is a bit easier to use since you do not need to define a equalityComparer, but less flexible since you can only have one IEquatable implementation. `SetEquals` will return true if the collections contain the same items, and false otherwise. – JonasH May 31 '21 at 11:42
  • I get an error: "**ObservableCollection does not contain a definition for ToHashSet...**". – Lucy82 May 31 '21 at 11:47
  • I tried with plain "**collection1.SequenceEqual(collection2, new EventModelEqualityComparer())**". It works somehow, but not for all cases. E.g. If **collection1** was null in some property at start and now I write some text in my UI and then delete text - then this property is no longer null, but my cloned collection is null. So I need to change equalitycomparer too. I hope you understand. – Lucy82 May 31 '21 at 11:54
  • 1
    @lucy82 [`ToHashSet`](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.tohashset?view=netframework-4.8) should be defined for all `IEnumerable`, including ObservableCollection, check that you have imported the correct namespaces and are using .Net 4.8 or later. Not sure what you mean with not working in all cases. the comparison code above should consider two objects equal if (and only if) all their properties are equal. – JonasH May 31 '21 at 12:15
  • I'm using .Net 4.5, that must be the case. However, I fixed all problems using "**SequenceEquals**". Will I have any problems If using this instead of **ToHashSet**? – Lucy82 May 31 '21 at 12:27
  • 1
    @Lucy82 Only if objects changes order, like removing one object and adding another identical one. – JonasH May 31 '21 at 12:46
  • Btw, how about simple `collection1.Except(collection2).Count()` ? Tried on an example [on that Fiddle](https://dotnetfiddle.net/H5zokx). It also doesn't worry about sorting. – Auditive May 31 '21 at 13:55
  • 1
    @Auditive `Except` would only check if all items in collection1 exists in collection2, but not the inverse, i.e. using set notation `collection1 ⊆ collection2` not `collection1 = collection2`. Note that you can trivially add an extension method: `ToHashSet(this IEnumerable e) => new HashSet(e);` – JonasH May 31 '21 at 14:24
  • Here is a useful link about refactoring tools Jonas mentioned in first comment: [check here](https://learn.microsoft.com/en-us/visualstudio/ide/reference/generate-equals-gethashcode-methods?view=vs-2019). So all this can be easily done via Visual Studio directly on a class Itself. I've tested that too, and It works same as provided answer. – Lucy82 Jun 01 '21 at 06:23