代码之家  ›  专栏  ›  技术社区  ›  James King

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

  •  4
  • James King  · 技术社区  · 9 年前

    尝试#3简化这个问题:

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

    直到你需要超越 .等于() 要实现值相等,在这一点上,默认比较器表示两个对象如果具有相同的值,则它们是相同的。我想不出哪种情况下,引用类型需要这样做。

    我从@Enigmativity听到的是 IEqualityComparer<StagingDataRow> 将为我的类型化DataRow提供一个默认相等比较器,该比较器将用于 Object 允许我在中实现值相等逻辑 StagingDataRow.Equals() .

    问题:

    1. 我理解得对吗?
    2. 我能保证.NET框架中的所有内容都会调用 EqualityComparer<StagingDataRow>.Equals() 而不是 暂存数据行.Equals() ?
    3. 应该做什么 IEqualityComparer<StagingDataRow>.GetHashCode(StagingDataRow obj) 哈希,并应返回与 StagingDataRow.GetHashCode() ?
    4. 传递给的内容 IEqualityComparer<StagingDataRow>。GetHashCode(StagingDataRow对象) ? 我要找的对象还是列表中的对象?二者都让实例方法接受自己作为参数是很奇怪的。。。

    通常,重写时如何将值相等与引用相等分开 .等于() ?



    引发此问题的原始代码行:

    //  For each ID, a collection of matching rows
    Dictionary<string, List<StagingDataRow>> stagingTableDictionary;
    
    
    StagingTableMatches.AddRange(stagingTableDictionary[perNr].Where(row => !StagingTableMatches.Contains(row)));
    
    .
    

    2 回复  |  直到 5 年前
        1
  •  4
  •   Community CDub    8 年前

    好吧,让我们先来处理一些误解:

    默认情况下, .Equals() 电话 .ReferenceEquals() 所以 .Contains() 仅当列表包含完全相同的对象时才会返回true。

    这是真的,但仅适用于引用类型。值类型将实现 very slow reflection-based Equals 函数的默认值,所以覆盖它符合您的最佳利益。

    我想不出哪种情况下,引用类型需要这样做。

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

    我从@Enigmativity听到的是 IEqualityComparer<StagingDataRow> 会给我打字 DataRow 一个默认的相等比较器,它将代替的默认比较器 Object 允许我在中实现值相等逻辑 StagingDataRow.Equals() .

    呃……不。

    IEqualityComaprer<T> 是一个接口,用于将相等比较委托给 不同的 对象如果你想要一个不同的 违约 实现类的行为 IEquatable<T> ,还委派 object.Equals 以保持一致性。实际上,超越 对象。等于 object.GetHashCode 足够的 更改默认的相等比较行为,但也要实现 IEquatable(可量化)<T> 还有其他好处:

    • 更明显的是,您的类型具有自定义的等式比较逻辑—考虑自文档化代码。
    • 它提高了值类型的性能,因为它避免了不必要的装箱(发生在 对象。等于 )

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

    我理解得对吗?

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

    谜题实际上建议您创建一个 不同的 实现的类型 IEqualityComparer<T> 看来你误解了那部分。

    我能保证.NET框架中的所有内容都会调用 EqualityComparer<StagingDataRow>.Equals() 而不是 暂存数据行.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对象) ? 我要找的对象还是列表中的对象?二者都让实例方法接受自己作为参数是很奇怪的。。。

    现在我希望你已经理解了实现 IEqualityComparer<T> 是一个 不同的 对象,所以这应该是有意义的。


    请阅读我的答案 Using of IEqualityComparer interface and EqualityComparer class in C# 以获取更深入的信息。

        2
  •  2
  •   D Stanley    9 年前

    我理解得对吗?

    部分-“默认” IEqualityComparer 将使用(按顺序):

    1. 实施 IEquatable<T>
    2. 重写的 Equals(object)
    3. 底座 object.Equals(object) ,这是引用类型的引用相等。

    我认为您混淆了在自定义类型中定义“相等”的两种不同方法。一是通过实施 IEquatable(可量化)<T> 它允许一个类型的实例确定它是否“等于”同一类型的另一个实例。

    另一个是 IEqualityComparer<T> 这是一个 独立的 确定是否 两个实例 那种类型的是相等的。

    所以如果你对 Equals 应适用 每当比较两个实例时 ,然后实施 IEquatable ,以及重写 等于 (实现后通常是微不足道的 IEquatable(可量化) )和 GetHashCode .

    如果您对“平等”的定义 仅适用于特定用例 ,然后创建 不同的 实现的类 IEqualityComparer<T> ,然后将其实例传递给所需的任何类或方法 那个 要应用的定义。

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

    否-仅接受的实例的类型和方法 IEquality比较器 因为参数会使用它。

    应该做什么 IEqualityComparer<StagingDataRow>.GetHashCode(StagingDataRow obj) 是否应该返回与StagingDataRow.GetHashCode()相同的值?

    它将计算传入对象的哈希代码。它不会将哈希代码与任何东西“比较”。它不必返回与重写的 方法 ,但它 必须 遵循以下规则 方法 特别是两个“相等”对象必须返回相同的哈希代码。

    让实例方法接受自己作为参数是很奇怪的。。。

    这就是为什么 IEquality比较器 通常在 不同的 班请注意 IEquatable(可量化)<T> 没有 GetHashCode() 方法,因为 它不需要一个 。它假设 方法 被重写以匹配的重写 object.Equals ,它应该与的强类型实现相匹配 IEquatable(可量化)<T>

    要旨

    如果希望将“等于”的定义作为该类型的默认值,请实现 IEquatable(可量化)<T> 和覆盖 等于 方法 。如果您希望仅针对特定用例定义“相等”,则创建一个 不同类别 实现 IEqualityComparer<T> 并将其实例传递给需要使用该定义的任何类型或方法。

    另外,我要指出,您很少直接调用这些方法(除了 等于 ). 它们通常由使用它们的方法调用(如 Contains )以确定两个对象是否“相等”或获取某个项的哈希代码。