泛型 List<T>.Contains() 中的值与引用相等

Jam*_*ing 6 c# linq iequatable iequalitycomparer gethashcode

尝试 #3 来简化这个问题:

\n

泛型List<T>可以包含任何类型 - 值或引用。当检查列表是否包含对象时,.Contains()使用类型 T 的默认值EqualityComparer<T>并调用.Equals()(这是我的理解)。如果没有定义 EqualityComparer,则默认比较器将调用.Equals(). 默认情况下,.Equals()调用.ReferenceEquals(), so.Contains()仅当列表包含完全相同的对象时才返回 true。

\n

直到您需要重写.Equals()以实现值相等,此时默认比较器表示如果两个对象具有相同的值,则它们是相同的。我想不出有哪一种情况适合引用类型。

\n

我从 @Enigmativity 听到的是,实现IEqualityComparer<StagingDataRow>将为我键入的 DataRow 提供一个默认的相等比较器,该比较器将用于代替Object\xe2\x80\x93 的默认比较器,从而允许我在StagingDataRow.Equals().

\n

问题:

\n
    \n
  1. 我的理解正确吗?
  2. \n
  3. 我能否保证 .NET 框架中的所有内容都会调用EqualityComparer<StagingDataRow>.Equals()而不是调用StagingDataRow.Equals()?
  4. \n
  5. 应该IEqualityComparer<StagingDataRow>.GetHashCode(StagingDataRow obj)哈希什么,它应该返回与 相同的值吗StagingDataRow.GetHashCode()?
  6. \n
  7. 传递给什么IEqualityComparer<StagingDataRow>.GetHashCode(StagingDataRow obj)?我正在寻找的对象还是列表中的对象?两个都?让实例方法接受自身作为参数会很奇怪......
  8. \n
\n

一般来说,在重写时如何区分值相等和引用相等.Equals()?

\n
\n
\n

引发这个问题的原始代码行:

\n
//  For each ID, a collection of matching rows\nDictionary<string, List<StagingDataRow>> stagingTableDictionary;\n\n\nStagingTableMatches.AddRange(stagingTableDictionary[perNr].Where(row => !StagingTableMatches.Contains(row)));\n\n.\n
Run Code Online (Sandbox Code Playgroud)\n
\n

Luc*_*ski 4

好吧,让我们先解决一些误解:

\n\n
\n

默认情况下,.Equals()调用.ReferenceEquals(), so.Contains()仅当列表包含完全相同的对象时才返回 true。

\n
\n\n

这是正确的,但仅适用于引用类型。值类型将实现非常慢的基于反射的Equals函数,因此覆盖它最符合您的利益。

\n\n
\n

我想不出有哪一种情况适合引用类型。

\n
\n\n

哦,我确信你可以...String例如是引用类型:)

\n\n
\n

我从 @Enigmativity 听到的是,实现IEqualityComparer<StagingDataRow>将为我输入DataRow一个默认的相等比较器,该比较器将用于代替Object\xe2\x80\x93 的默认比较器,从而允许我在StagingDataRow.Equals().

\n
\n\n

呃……不。

\n\n

IEqualityComaprer<T>是一个接口,可让您将相等比较委托给不同的对象。如果您希望您的类有不同的默认IEquatable<T>行为,您可以实现,并委托object.Equals给它以保持一致性。实际上,覆盖object.Equalsandobject.GetHashCode足以改变默认的相等比较行为,而且实现还有额外的好处:IEquatable<T>

\n\n
    \n
  • 它使您的类型具有自定义相等比较逻辑变得更加明显 - 想想自记录代码。
  • \n
  • 它提高了值类型的性能,因为它避免了不必要的装箱(发生在object.Equals)
  • \n
\n\n

因此,对于您的实际问题:

\n\n
\n

我的理解正确吗?

\n
\n\n

您似乎对此仍然有点困惑,但不用担心:)

\n\n

Enigmativity 实际上建议您创建一个实现IEqualityComparer<T>. 看来你误解了那部分。

\n\n
\n

我是否保证 .NET 框架中的所有内容都会调用EqualityComparer<StagingDataRow>.Equals()而不是StagingDataRow.Equals()

\n
\n\n

默认情况下,(正确编写的)框架数据结构会将相等比较委托给EqualityComparer<StagingDataRow>.Default,而后者又会委托给StagingDataRow.Equals。

\n\n
\n

应该IEqualityComparer<StagingDataRow>.GetHashCode(StagingDataRow obj)哈希什么,它应该返回与以下内容相同的值StagingDataRow.GetHashCode()

\n
\n\n

不必要。它应该是自洽的:如果myEqualitycomaprer.Equals(a, b)那么你必须确保myEqualitycomaprer.GetHashCode(a) == myEqualitycomaprer.GetHashCode(b).

\n\n

它可以是与 相同的实现StagingDataRow.GetHashCode,但不一定。

\n\n
\n

传递给什么IEqualityComparer<StagingDataRow>.GetHashCode(StagingDataRow obj)?我正在寻找的对象还是列表中的对象?两个都?让实例方法接受自身作为参数会很奇怪......

\n
\n\n

好吧,现在我希望你已经明白实现的对象IEqualityComparer<T>是一个不同的对象,所以这应该是有道理的。

\n\n
\n\n

请阅读我关于在 C# 中使用 IEqualityComparer 接口和 EqualityComparer 类的答案,以获取更深入的信息。

\n