通用List<T>
可以包含任何类型 - 值或引用。在检查列表是否包含对象时,.Contains()
对类型T使用默认EqualityComparer<T>
,并调用.Equals()
(我的理解)。如果未定义EqualityComparer,则默认比较器将调用.Equals()
。默认情况下,.Equals()
会调用.ReferenceEquals()
,因此如果列表包含完全相同的对象,.Contains()
将仅返回true。
在您需要覆盖.Equals()
以实现值相等之前,默认比较器表示如果两个对象具有相同的值,则它们是相同的。我想不出一个单一的案例,那里的参考类型是可取的。
我从@Enigmativity听到的是,实现IEqualityComparer<StagingDataRow>
将为我的类型化DataRow提供一个默认的相等比较器,它将被用来代替Object
的默认比较器 - 允许我实现值相等StagingDataRow.Equals()
中的逻辑。
问题:
EqualityComparer<StagingDataRow>.Equals()
而不是StagingDataRow.Equals()
吗?IEqualityComparer<StagingDataRow>.GetHashCode(StagingDataRow obj)
应该对哪些内容进行哈希处理?它应该返回与StagingDataRow.GetHashCode()
相同的值吗?IEqualityComparer<StagingDataRow>.GetHashCode(StagingDataRow obj)
的内容是什么?我正在寻找的对象或列表中的对象?都?让实例方法接受自己作为参数...... 通常,在覆盖.Equals()
时,如何将一个值与引用相等分开?
原始的代码行引发了这个问题:
// For each ID, a collection of matching rows
Dictionary<string, List<StagingDataRow>> stagingTableDictionary;
StagingTableMatches.AddRange(stagingTableDictionary[perNr].Where(row => !StagingTableMatches.Contains(row)));
.
答案 0 :(得分:2)
我理解正确吗?
部分 - “默认”IEqualityComparer
将使用(按顺序):
IEquatable<T>
Equals(object)
object.Equals(object)
,它是引用类型的引用相等。我认为你混淆了两种在自定义类型中定义“相等”的方法。一种是通过实现IEquatable<T>
,它允许类型的实例确定它是否与同一类型的另一个实例“相等”。
另一个是IEqualityComparer<T>
,它是独立的接口,用于确定该类型的两个实例是否相等。
因此,如果您在比较两个实例时定义Equals
应该应用,那么请实施IEquatable
,以及覆盖Equals
(通常是实施IEquatable
)和GetHashCode
之后的微不足道。
如果“equal”的定义仅适用于特定用例,则创建一个实现IEqualityComparer<T>
的不同的类,然后传递一个实例它适用于您希望 定义应用于的任何类或方法。
我保证.NET框架中的所有内容都会调用
EqualityComparer<StagingDataRow>.Equals()
而不是StagingDataRow.Equals()
吗?
否 - 仅接受IEqualityComparer
实例作为参数的类型和方法将使用它。
IEqualityComparer<StagingDataRow>.GetHashCode(StagingDataRow obj)
应该如何散列,是否应该返回与StagingDataRow.GetHashCode()相同的值?
它将计算传入的对象的哈希码。它不会将哈希码“比较”为任何东西。它不一定必须返回与被覆盖的GetHashCode
相同的值,但必须遵循GetHashCode
的规则,特别是两个“相等”对象必须返回相同的值哈希码。
将实例方法接受为参数...
会很奇怪
这就是为什么IEqualityComparer
通常在不同的类上实现的原因。请注意,IEquatable<T>
没有GetHashCode()
方法,因为它不需要一个。它假定覆盖GetHashCode
以匹配object.Equals
的覆盖,该覆盖应与IEquatable<T>
的强类型实现相匹配
底线
如果您希望“等于”的定义为该类型的默认值,请实施IEquatable<T>
并覆盖Equals
和GetHashCode
。如果你想要一个仅用于特定用例的“相等”的定义,那么创建一个实现IEqualityComparer<T>
的不同的类,并将它的实例传递给任何需要的类型或方法使用那个定义。
另外,我会注意到你很少直接调用这些方法(Equals
除外)。它们通常由使用它们的方法(如Contains
)调用,以确定两个对象是否“相等”或获取项目的哈希码。
答案 1 :(得分:1)
好的,让我们先处理一些误解:
默认情况下,
.Equals()
会调用.ReferenceEquals()
,因此如果列表包含完全相同的对象,.Contains()
将仅返回true。
这是事实,但仅适用于参考类型。值类型默认会实现very slow reflection-based Equals
函数,因此最好覆盖它。
我无法想到一个单一的案例,那里的参考类型是可取的。
哦,我确信你可以...... String
是一个引用类型,例如:)
我从@Enigmativity听到的是,实现
IEqualityComparer<StagingDataRow>
将为我的类型DataRow
提供一个默认的相等比较器,而不是Object
的默认比较器 - 允许我在StagingDataRow.Equals()
中实现值相等逻辑。
错误......不。
IEqualityComaprer<T>
是一个接口,允许您将相等比较委托给不同的对象。如果您希望为您的类提供不同的默认行为,请实施IEquatable<T>
,并将object.Equals
委托给它以保持一致性。实际上,覆盖object.Equals
和object.GetHashCode
足以更改默认的相等比较行为,但实施IEquatable<T>
还有其他好处:
object.Equals
时发生)所以,对于你的实际问题:
我理解正确吗?
你似乎对此有点困惑,但不要担心:)
Enigmativity实际上建议您创建一个实现IEqualityComparer<T>
的不同的类型。看起来你误解了这一部分。
我保证.NET框架中的所有内容都会调用
EqualityComparer<StagingDataRow>.Equals()
而不是StagingDataRow.Equals()
默认情况下,(正确编写的)框架数据结构会将相等性比较委托给EqualityComparer<StagingDataRow>.Default
,后者将委托给StagingDataRow.Equals
。
IEqualityComparer<StagingDataRow>.GetHashCode(StagingDataRow obj)
应该对哪些内容进行哈希处理,并且应该返回与StagingDataRow.GetHashCode()
相同的值
不一定。它应该是自洽的:如果myEqualitycomaprer.Equals(a, b)
,那么必须确保myEqualitycomaprer.GetHashCode(a) == myEqualitycomaprer.GetHashCode(b)
。
可以与StagingDataRow.GetHashCode
相同,但不一定。
传递给
IEqualityComparer<StagingDataRow>.GetHashCode(StagingDataRow obj)
的内容是什么?我正在寻找的对象或列表中的对象?都?让一个实例方法接受自己作为参数......会很奇怪。
好吧,到现在为止,我希望您已经了解实现IEqualityComparer<T>
的对象是不同的对象,所以这应该是有意义的。
请阅读Using of IEqualityComparer interface and EqualityComparer class in C#上的答案,了解更多深入信息。