何时使用IEquatable以及为什么

时间:2020-12-30 16:10:18

I just dont understand this - What does IEquatable buy you exactly??

我只是不明白——我能为你买什么?

The only reason I can see it being useful is when creating a generic type and forcing users to implement and write a good equals method.

我能看到它有用的唯一原因是创建泛型类型并强制用户实现和编写一个良好的equals方法。

What am I missing

我失踪

4 个解决方案

#1


32  

From the MSDN:

从MSDN:

The IEquatable(T) interface is used by generic collection objects such as Dictionary(TKey, TValue), List(T), and LinkedList(T) when testing for equality in such methods as Contains, IndexOf, LastIndexOf, and Remove.

IEquatable(T)接口用于通用集合对象,如Dictionary(TKey, TValue)、List(T)和LinkedList(T)。

The IEquatable<T> implementation will require one less cast for these classes and as a result will be slightly faster than the standard object.Equals method that would be used otherwise. As an example see the different implementation of the two methods:

IEquatable 实现将要求对这些类进行较少的转换,结果将比标准对象稍微快一些。否则将使用的Equals方法。举个例子,看看这两种方法的不同实现方式:

public bool Equals(T other) 
{
  if (other == null) 
     return false;

  return (this.Id == other.Id);
}

public override bool Equals(Object obj)
{
  if (obj == null) 
     return false;

  T tObj = obj as T;  // The extra cast
  if (tObj == null)
     return false;
  else   
     return this.Id == tObj.Id;
}

#2


23  

I'm amazed that the most important reason is not mentioned here.

我很惊讶,最重要的原因没有提到这里。

IEquatable<> was introduced mainly for structs for two reasons:

IEquatable<>主要是针对结构体引入的,原因有两个:

  1. For value types (read structs) the non-generic Equals(object) requires boxing. IEquatable<> lets a structure implement a strongly typed Equals method so that no boxing is required.

    对于值类型(读结构),非泛型等号(对象)需要装箱。IEquatable<>允许结构实现强类型的Equals方法,因此不需要装箱。

  2. For structs, the default implementation of Object.Equals(Object) (which is the overridden version in System.ValueType) performs a value equality check by using reflection to compare the values of every field in the type. When an implementer overrides the virtual Equals method in a struct, the purpose is to provide a more efficient means of performing the value equality check and optionally to base the comparison on some subset of the struct's field or properties.

    对于struct, Object. equals (Object)的默认实现(System.ValueType中的重写版本)通过使用反射来比较类型中每个字段的值,执行值相等检查。当实现者重写结构中的virtual Equals方法时,其目的是提供一种更有效的方法来执行值相等检查,并可选地将比较建立在结构体字段或属性的某个子集上。

Both of which improves performance.

两者都能提高性能。

Reference types (read classes) don't benefit as much. The IEquatable<> implementation does let you avoid a cast from System.Object but that's a very trivial gain. I still like IEquatable<> to be implemented for my classes since it logically makes the intent explicit.

引用类型(读类)没有那么大的好处。IEquatable<>实现可以避免系统强制转换。但这是一个很小的增益。我仍然喜欢为我的类实现IEquatable<>,因为它在逻辑上明确了意图。

#3


11  

I use IEquatable<T> quite a lot, although from a pure technical perspective, it doesn't really give me any particular benefits. Overriding System.Object.Equals can provide you with the same functionality.

我经常使用IEquatable ,尽管从纯技术的角度来看,它并没有给我带来什么特别的好处。覆盖System.Object。Equals可以为您提供相同的功能。

However, I like the explicitness of implementing IEquatable<T>. I use the concepts of Entities and Value Objects from Domain-Driven Design quite a lot, and use IEquatable<T> particularly for Value Objects, simply because it signals that a type has well-defined equality.

但是,我喜欢实现IEquatable 的明确性。我大量使用了域驱动设计中的实体和值对象的概念,并对值对象使用了IEquatable ,这仅仅是因为它表明一个类型具有定义良好的等式。

#4


0  

Further to the other answers here's a very good reason to be implementing IEquatable<T> (and obviously overriding Equals(object) too) for value types. Just look at the default ValueType.Equals(object) code that gets called otherwise. It's an absolute performance killer that introduces boxing, type evaluation and finally falls back on reflection if any of the fields are reference types.

对于其他答案,这里有一个很好的理由来实现值类型的IEquatable (显然也会重写Equals(object))。看看默认的ValueType.Equals(object)代码,否则它会被调用。它是一种绝对的性能杀手,它引入了装箱、类型评估,并且如果任何字段都是引用类型,那么它最终会返回到反射。

public override bool Equals(object obj)
{
    if (obj == null)
    {
        return false;
    }
    RuntimeType type = (RuntimeType) base.GetType();
    RuntimeType type2 = (RuntimeType) obj.GetType();
    if (type2 != type)
    {
        return false;
    }
    object a = this;
    if (CanCompareBits(this))
    {
        return FastEqualsCheck(a, obj);
    }
    FieldInfo[] fields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
    for (int i = 0; i < fields.Length; i++)
    {
        object obj3 = ((RtFieldInfo) fields[i]).UnsafeGetValue(a);
        object obj4 = ((RtFieldInfo) fields[i]).UnsafeGetValue(obj);
        if (obj3 == null)
        {
            if (obj4 != null)
            {
                return false;
            }
        }
        else if (!obj3.Equals(obj4))
        {
            return false;
        }
    }
    return true;
}

In certain scenarios (such as using the value type as a key in a dictionary) it can murder performance in one foul swoop.

在某些场景中(例如在字典中使用值类型作为键),它可以在一次恶意突袭中破坏性能。

#1


32  

From the MSDN:

从MSDN:

The IEquatable(T) interface is used by generic collection objects such as Dictionary(TKey, TValue), List(T), and LinkedList(T) when testing for equality in such methods as Contains, IndexOf, LastIndexOf, and Remove.

IEquatable(T)接口用于通用集合对象,如Dictionary(TKey, TValue)、List(T)和LinkedList(T)。

The IEquatable<T> implementation will require one less cast for these classes and as a result will be slightly faster than the standard object.Equals method that would be used otherwise. As an example see the different implementation of the two methods:

IEquatable 实现将要求对这些类进行较少的转换,结果将比标准对象稍微快一些。否则将使用的Equals方法。举个例子,看看这两种方法的不同实现方式:

public bool Equals(T other) 
{
  if (other == null) 
     return false;

  return (this.Id == other.Id);
}

public override bool Equals(Object obj)
{
  if (obj == null) 
     return false;

  T tObj = obj as T;  // The extra cast
  if (tObj == null)
     return false;
  else   
     return this.Id == tObj.Id;
}

#2


23  

I'm amazed that the most important reason is not mentioned here.

我很惊讶,最重要的原因没有提到这里。

IEquatable<> was introduced mainly for structs for two reasons:

IEquatable<>主要是针对结构体引入的,原因有两个:

  1. For value types (read structs) the non-generic Equals(object) requires boxing. IEquatable<> lets a structure implement a strongly typed Equals method so that no boxing is required.

    对于值类型(读结构),非泛型等号(对象)需要装箱。IEquatable<>允许结构实现强类型的Equals方法,因此不需要装箱。

  2. For structs, the default implementation of Object.Equals(Object) (which is the overridden version in System.ValueType) performs a value equality check by using reflection to compare the values of every field in the type. When an implementer overrides the virtual Equals method in a struct, the purpose is to provide a more efficient means of performing the value equality check and optionally to base the comparison on some subset of the struct's field or properties.

    对于struct, Object. equals (Object)的默认实现(System.ValueType中的重写版本)通过使用反射来比较类型中每个字段的值,执行值相等检查。当实现者重写结构中的virtual Equals方法时,其目的是提供一种更有效的方法来执行值相等检查,并可选地将比较建立在结构体字段或属性的某个子集上。

Both of which improves performance.

两者都能提高性能。

Reference types (read classes) don't benefit as much. The IEquatable<> implementation does let you avoid a cast from System.Object but that's a very trivial gain. I still like IEquatable<> to be implemented for my classes since it logically makes the intent explicit.

引用类型(读类)没有那么大的好处。IEquatable<>实现可以避免系统强制转换。但这是一个很小的增益。我仍然喜欢为我的类实现IEquatable<>,因为它在逻辑上明确了意图。

#3


11  

I use IEquatable<T> quite a lot, although from a pure technical perspective, it doesn't really give me any particular benefits. Overriding System.Object.Equals can provide you with the same functionality.

我经常使用IEquatable ,尽管从纯技术的角度来看,它并没有给我带来什么特别的好处。覆盖System.Object。Equals可以为您提供相同的功能。

However, I like the explicitness of implementing IEquatable<T>. I use the concepts of Entities and Value Objects from Domain-Driven Design quite a lot, and use IEquatable<T> particularly for Value Objects, simply because it signals that a type has well-defined equality.

但是,我喜欢实现IEquatable 的明确性。我大量使用了域驱动设计中的实体和值对象的概念,并对值对象使用了IEquatable ,这仅仅是因为它表明一个类型具有定义良好的等式。

#4


0  

Further to the other answers here's a very good reason to be implementing IEquatable<T> (and obviously overriding Equals(object) too) for value types. Just look at the default ValueType.Equals(object) code that gets called otherwise. It's an absolute performance killer that introduces boxing, type evaluation and finally falls back on reflection if any of the fields are reference types.

对于其他答案,这里有一个很好的理由来实现值类型的IEquatable (显然也会重写Equals(object))。看看默认的ValueType.Equals(object)代码,否则它会被调用。它是一种绝对的性能杀手,它引入了装箱、类型评估,并且如果任何字段都是引用类型,那么它最终会返回到反射。

public override bool Equals(object obj)
{
    if (obj == null)
    {
        return false;
    }
    RuntimeType type = (RuntimeType) base.GetType();
    RuntimeType type2 = (RuntimeType) obj.GetType();
    if (type2 != type)
    {
        return false;
    }
    object a = this;
    if (CanCompareBits(this))
    {
        return FastEqualsCheck(a, obj);
    }
    FieldInfo[] fields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
    for (int i = 0; i < fields.Length; i++)
    {
        object obj3 = ((RtFieldInfo) fields[i]).UnsafeGetValue(a);
        object obj4 = ((RtFieldInfo) fields[i]).UnsafeGetValue(obj);
        if (obj3 == null)
        {
            if (obj4 != null)
            {
                return false;
            }
        }
        else if (!obj3.Equals(obj4))
        {
            return false;
        }
    }
    return true;
}

In certain scenarios (such as using the value type as a key in a dictionary) it can murder performance in one foul swoop.

在某些场景中(例如在字典中使用值类型作为键),它可以在一次恶意突袭中破坏性能。