preferring EqualityComparer< T>到的IEqualityComparer< T>EqualityComparer、preferring、LT、IEq

2023-09-02 01:46:39 作者:帅得不明显

在IEqualityComparer<T>备注部分MSDN上:

  

我们建议您从派生   EqualityComparer&LT; T>类,而不是   实现的IEqualityComparer&LT; T>   接口,因为   EqualityComparer&LT; T>类测试   平等使用   IEquatable&LT; T> .Equals方法而不是   该方法的Object.Equals。 ......

我不明白为什么我们要preFER报价的说法,从 EqualityComparer&LT得出; T&GT; 类代替实施的IEqualityComparer&LT; T&GT; 。这意味着,对象实施的IEqualityComparer&LT; T&GT; 使用将测试相等的Object.Equals ,但不是全部点实施的IEqualityComparer&LT; T&GT; 的时候,我们不希望使用来测试相等的Object.Equals IEquatable&LT; T&GT; .Equals

这也意味着,如果我们从得到 EqualityComparer&LT; T&GT; ,然后派生类将使用测试相等 IEquatable&LT; T&GT; .Equals 方法。再次,是不是从 EqualityComparer&LT得出的整点; T&GT; 的时候,我们不希望使用来测试相等的Object.Equals IEquatable&LT; T&GT; .Equals (因为 EqualityComparer&LT; T&GT; .DEFAULT 已经测试使用的Object.Equals IEquatable&LT; T&GT; .Equals

  

...这是一致的   含有的IndexOf,LastIndexOf和   删除词典&LT的方法; TKEY的,   TValue>中类和其他通用   集合。

我想大多数集合在.NET库测试的默认的元素平等(即当用户不提供自己的自定义的IEqualityComparer&LT; T&GT; 对象来这些藏品),通过调用 IEquatable&LT; T&GT; .Equals 的Object.Equals (根据类型与否的要素 T 实施 IEquatable&LT; T&GT; )通过 EqualityComparer&LT; T&GT; .DEFAULT

为什么不把这些藏品(测试的默认的平等时)调用 IEquatable&LT; T&GT; .Equals 的Object.Equals ,而不是直接通过 EqualityComparer&LT; T&GT; .DEFAULT

解决方案

关于你的第一个问题:

它说有,因为的IEqualityComparer&LT两种方法实际上是无用的; T&GT; 接口被标记为抽象的。他们都没有一个默认的实现,你会无论如何也要覆盖它。如果有的话,推理,他们已经在这里提供听起来更像是一个什么样的comparers的的指导方针可能的做的,无关其实际作用。

纵观 EqualityComparer&LT的公共/保护的接口; T&GT; 类,但只有一个可取之处,它实现了非一般的的IEqualityComparer 接口。我想他们的意思是说,他们推荐它,因为 EqualityComparer&LT; T&GT; 实际上实现非泛型的IEqualityComparer 接口这样你的类可以被用在了非一般的比较器是必需的。

它更有意义的 的IComparer&LT; T&GT; 的言论部分:

  

我们建议您从比较器&LT得出; T>类,而不是实现的IComparer&LT; T>接口,因为比较器&LT; T>类提供了IComparer.Compare方法的显式接口实现和得到默认属性默认比较的对象。

我怀疑它应该说类似的东西了的IEqualityComparer&LT; T&GT; ,但一些想法混合四周,最后有一个不完整的描述

关于你提到的第二个问题:

在库中找到的集合的主要目的是要尽可能地灵活。获取的方法之一就是允许通过提供一个的IComparer&LT比较它们内部对象的自定义方式; T&GT; 的IEqualityComparer&LT; T&GT; 做比较。这将是更容易得到一个默认的比较实例,当一个人没有提供比它是直接做比较。这些comparers反过来可能包括需要调用包装精美的相应的比较逻辑。

例如,该comparers可以确定 T 是否为 IEquatable&LT; T&GT; 并调用 IEquatable&LT; T&GT; .Equals 的对象或以其它方式使用的Object.Equals 。在这里更好的封装比在集合code可能反复比较器。

另外,如果他们想依傍调用 IEquatable&LT; T&GT; .Equals 直接,他们将不得不增加一个约束的 T 这将使该呼叫成为可能。这样做使得它不够灵活,否定提供的比较器摆在首位的好处。

澳洲VCE中数MM Y11 13E F log inequality log graph

From the IEqualityComparer<T> remarks section on MSDN:

We recommend that you derive from the EqualityComparer<T> class instead of implementing the IEqualityComparer<T> interface, because the EqualityComparer<T> class tests for equality using the IEquatable<T>.Equals method instead of the Object.Equals method. ...

I don't understand the quote's argument of why we would should prefer to derive from EqualityComparer<T> class instead of implementing IEqualityComparer<T>. It implies that objects implementing IEqualityComparer<T> will test for equality using Object.Equals, but isn't the whole point of implementing IEqualityComparer<T> when we don't want to test for equality using Object.Equals or IEquatable<T>.Equals?

It also implies that if we derive from EqualityComparer<T>, then derived class will test for equality using IEquatable<T>.Equals method. Again, isn't the whole point of deriving from EqualityComparer<T> when we don't want to test for equality using Object.Equals or IEquatable<T>.Equals (since EqualityComparer<T>.Default already test using Object.Equals or IEquatable<T>.Equals)?

... This is consistent with the Contains, IndexOf, LastIndexOf, and Remove methods of the Dictionary<TKey, TValue> class and other generic collections.

I assume most collections in the .NET library test for default equality of elements (i.e. when users don't provide their own custom IEqualityComparer<T> objects to these collections) by calling IEquatable<T>.Equals or Object.Equals (depending on whether or not elements of type T implement IEquatable<T>) via EqualityComparer<T>.Default.

Why don't these collections (when testing for default equality) call IEquatable<T>.Equals or Object.Equals directly instead of via EqualityComparer<T>.Default class?

解决方案

Regarding your first question:

What it says there is practically useless since both methods of the IEqualityComparer<T> interface are marked abstract. They both don't have a "default" implementation and you would have to override it anyway. If anything, the "reasoning" they've provided here sound more like a guideline of what your comparers could do and is irrelevant to what it actually does.

Looking at the public/protected interface of the EqualityComparer<T> class, there's only one redeeming quality, it implements the non-generic IEqualityComparer interface. I think what they meant to say that they recommend it because EqualityComparer<T> actually implements the non-generic IEqualityComparer interface that way your class may be used where the non-generic comparer is required.

It makes more sense in IComparer<T>'s remarks section:

We recommend that you derive from the Comparer<T> class instead of implementing the IComparer<T> interface, because the Comparer<T> class provides an explicit interface implementation of the IComparer.Compare method and the Default property that gets the default comparer for the object.

I suspect it was supposed to say something similar for IEqualityComparer<T> but some ideas were mixed around and ended up having an incomplete description.

Regarding your second question:

A primary goal for the collections found in the library was to be as flexible as possible. One way to get that is to allow custom ways of comparing objects within them by providing a IComparer<T> or IEqualityComparer<T> to do the comparisons. It would be much more easier to get an instance of a default comparer when one was not supplied than it is to do the comparisons directly. These comparers in turn could include the logic necessary to call the appropriate comparisons packaged nicely.

e.g., The comparers can determine whether T is IEquatable<T> and call IEquatable<T>.Equals on the object or otherwise use Object.Equals. Better encapsulated here in the comparer than it is potentially repeated in the collections code.

Besides, if they wanted to fall back on calling IEquatable<T>.Equals directly, they would have to add a constraint on T that would make this call possible. Doing so makes it less flexible and negates the benefits of providing the comparer in the first place.