Attempt #3 to simplify this question:
A generic List<T>
can contain any type - value or reference. When checking to see if a list contains an object, .Contains()
uses the default EqualityComparer<T>
for type T, and calls .Equals()
(is my understanding). If no EqualityComparer has been defined, the default comparer will call .Equals()
. By default, .Equals()
calls .ReferenceEquals()
, so .Contains()
will only return true if the list contains the exact same object.
Until you need to override .Equals()
to implement value equality, at which point the default comparer says two objects are the same if they have the same values. I can't think of a single case where that would be desirable for a reference type.
What I'm hearing from @Enigmativity is that implementing IEqualityComparer<StagingDataRow>
will give my typed DataRow a default equality comparer that will be used instead of the default comparer for Object
– allowing me to implement value equality logic in StagingDataRow.Equals()
.
Questions:
- Am I understanding that correctly?
- Am I guaranteed that everything in the .NET framework will call
EqualityComparer<StagingDataRow>.Equals()
instead ofStagingDataRow.Equals()
? - What should
IEqualityComparer<StagingDataRow>.GetHashCode(StagingDataRow obj)
hash against, and should it return the same value asStagingDataRow.GetHashCode()
? - What is passed to
IEqualityComparer<StagingDataRow>.GetHashCode(StagingDataRow obj)
? The object I'm looking for or the object in the list? Both? It would be strange to have an instance method accept itself as a parameter...
In general, how does one separate value equality from reference equality when overriding .Equals()
?
The original line of code spurring this question:
// For each ID, a collection of matching rows
Dictionary<string, List<StagingDataRow>> stagingTableDictionary;
StagingTableMatches.AddRange(stagingTableDictionary[perNr].Where(row => !StagingTableMatches.Contains(row)));
.
DataRow
and override the equality methods? Or do you plan to create a customIEqualityComparer
? Where are you changing the data in theDataRow
? Where is the code that needs to to compareDataRows
based on values? – ThrombosisIEqualityComparer<DataRow>
instance and use that in your queries. – RefillIEqualityComparer
in a linq query. The code that compares these would just be anif(row.equals(otherrow))
. The issue is the.Where(match => !DatafeedRow.StagingTableMatches.Contains(match))
. If linq would use the customIEqualityComparer
for that, then I could override.Equals()
. But that seems to be asking for trouble - I'd have to guarantee that any code written against those DataRows would use my custom comparer. – BinningsDataRow
. – BinningsDataRowSubClass
class. You have to put them into two differentIEqualityComparer
s. Or you can put one way of comparing intoDataRowSubClass
and another one into its ownIEqualityComparer
. It is a rule thatGetHashCode
should return the same value for two objects thatEquals
return true for. – ThrombosisEnumerable.Contains(
that takes in a equality comparer, then it does not matter what the default comparer is. – ConnaughtEquals
andGetHashCode
and implementIEquatable
, notIEqualityComparer
. – Rector.Equals
without also overriding.GetHashCode
- if you don't you will break equality. However, the value ofGetHashCode
mustn't change throughout the usage of the object if it is used in any structure or query that calls.GetHashCode
. Therefore, you can only safely use immutable values to compute the hash code. So your only safe choice is to implement your ownIEqualityComparer<DataRow>
to handle this situation. – RefillStagingTableMatches
should be aHashSet<T>
rather than a list. You can specify an equality comparer if required. – Sphacelus