通用List.Contains()中的值与引用相等
作者:互联网
尝试#3简化此问题:
通用列表< T>可以包含任何类型-值或引用.当检查列表是否包含对象时,.Contains()使用默认的EqualityComparer< T>. T类型,并调用.Equals()(据我理解).如果未定义EqualityComparer,则默认比较器将调用.Equals().默认情况下,.Equals()调用.ReferenceEquals(),因此.Contains()仅在列表包含完全相同的对象时才返回true.
在需要重写.Equals()来实现值相等之前,默认情况下,默认比较器会说两个对象具有相同的值,则它们是相同的.我想不出哪一种情况对于引用类型来说是理想的.
我从@Enigmativity那里听到的是,实现IEqualityComparer< StagingDataRow>将为我键入的DataRow提供一个默认的相等比较器,而不是Object的默认比较器-允许我在StagingDataRow.Equals()中实现值相等逻辑.
问题:
>我理解正确吗?
>我是否保证.NET框架中的所有内容都将调用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)));
.
解决方法:
好的,让我们先处理一些误解:
By default,
.Equals()
calls.ReferenceEquals()
, so.Contains()
will only return true if the list contains the exact same object.
这是正确的,但仅适用于引用类型.值类型默认情况下将实现very slow reflection-based Equals
函数,因此,您最好将其覆盖.
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 typedDataRow
a default equality comparer that will be used instead of the default comparer forObject
– allowing me to implement value equality logic inStagingDataRow.Equals()
.
嗯…不
IEqualityComaprer< T>是一个接口,可让您将相等性比较委派给其他对象.如果您希望类使用其他默认行为,则可以实现IEquatable< T>并委托对象.实际上,覆盖object.Equals和object.GetHashCode足以更改默认的相等比较行为,而且还可以实现IEquatable< T>.还有其他好处:
>显然,您的类型具有自定义的相等比较逻辑-考虑自记录代码.
>它提高了值类型的性能,因为它避免了不必要的装箱(这在object.Equals中发生)
因此,对于您的实际问题:
Am I understanding that correctly?
您似乎对此仍然有些困惑,但是请放心:)
谜题实际上建议您创建实现IEqualityComparer< T>的其他类型.好像您误解了那部分.
Am I guaranteed that everything in the .NET framework will call
EqualityComparer<StagingDataRow>.Equals()
instead ofStagingDataRow.Equals()
默认情况下,(正确编写的)框架数据结构将把相等性比较委托给EqualityComparer< StagingDataRow> .Default,它将依次委托给StagingDataRow.Equals.
What should
IEqualityComparer<StagingDataRow>.GetHashCode(StagingDataRow obj)
hash against, and should it return the same value asStagingDataRow.GetHashCode()
不必要.它应该是自洽的:如果myEqualitycomaprer.Equals(a,b),则必须确保myEqualitycomaprer.GetHashCode(a)== myEqualitycomaprer.GetHashCode(b).
它可以是与StagingDataRow.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…
好吧,到目前为止,我希望您已经了解实现IEqualityComparer< T>的对象.是一个不同的对象,所以这应该是有道理的.
请阅读我对Using of IEqualityComparer interface and EqualityComparer class in C#的回答,以获取更深入的信息.
标签:gethashcode,iequatable,iequalitycomparer,linq,c 来源: https://codeday.me/bug/20191118/2029807.html