什么是使用的IEqualityComparer<推荐的最佳做法; T> ;?
我正在寻找现实世界中的最佳实践,别人怎么可能有复杂的领域实施的解决方案。
I'm looking for real world best practices, how other people might have implemented solutions with complex domains.
任何时候你可以考虑使用的IEqualityComparer< T>
,停下来想,如果这个类可以作出实施 IEquatable< T>
来代替。如果产品
应该总是通过ID进行比较,只是把它定义为等同这样,所以你可以使用默认的比较。
Any time you consider using an IEqualityComparer<T>
, pause to think if the class could be made to implement IEquatable<T>
instead. If a Product
should always be compared by ID, just define it to be equated as such so you can use the default comparer.
不过,还是有一些原因,你可能想自定义比较:
That said, there are still a few of reasons you might want a custom comparer:
- 如果有多种方式实例一类可被认为是相等的。这样做的最好的例子是一个字符串,为此,该框架提供的
StringComparer
。 - 如果该类以这样的方式定义的,你不能把它定义为
IEquatable< T>
。这将包括由编译器(特别是匿名类型,默认情况下使用属性明智的比较)产生别人和类定义的类。
- If there are multiple ways instances of a class could be considered equal. The best example of this is a string, for which the framework provides six different comparers in
StringComparer
. - If the class is defined in such a way that you can't define it as
IEquatable<T>
. This would include classes defined by others and classes generated by the compiler (specifically anonymous types, which use a property-wise comparison by default).
如果你决定你需要一个比较器,你当然可以用广义的比较器(见DMenT的答案),但如果你需要重新使用逻辑应该封装在一个专用的类。你甚至可以通过从通用基继承声明它:
If you do decide you need a comparer, you can certainly use a generalized comparer (see DMenT's answer), but if you need to reuse that logic you should encapsulate it in a dedicated class. You could even declare it by inheriting from the generic base:
class ProductByIdComparer : GenericEqualityComparer<ShopByProduct>
{
public ProductByIdComparer()
: base((x, y) => x.ProductId == y.ProductId, z => z.ProductId)
{ }
}
至于使用,您应该利用comparers的可能时。例如,而不是调用 ToLower将()
在作为字典的键每个字符串(其逻辑将在您的应用程序,简直是俯拾即是),你应该申报字典使用不区分大小写 StringComparer
。这同样适用于LINQ的运营商接受一个比较器。但同样,始终考虑如果equatable行为应该是内在的类,而不是外部定义的。
As far as use, you should take advantage of comparers when possible. For example, rather than calling ToLower()
on every string used as a dictionary key (logic for which will be strewn across your app), you should declare the dictionary to use a case-insensitive StringComparer
. The same goes for the LINQ operators that accept a comparer. But again, always consider if the equatable behavior that should be intrinsic to the class rather than defined externally.