为什么要实施公平教育?接口

本文关键字:接口 施公平 为什么 | 更新日期: 2023-09-27 18:11:06

我一直在阅读文章并在一定程度上理解接口,但是,如果我想纠正我自己的自定义Equals方法,似乎我可以在不实现等价接口的情况下做到这一点。一个例子。

using System;
using System.Collections;
using System.ComponentModel;
namespace ProviderJSONConverter.Data.Components
{
    public class Address : IEquatable<Address>
    {
        public string address { get; set; }
        [DefaultValue("")]
        public string address_2 { get; set; }
        public string city { get; set; }
        public string state { get; set; }
        public string zip { get; set; }
        public bool Equals(Address other)
        {
            if (Object.ReferenceEquals(other, null)) return false;
            if (Object.ReferenceEquals(this, other)) return true;
            return (this.address.Equals(other.address)
                && this.address_2.Equals(other.address_2)
                && this.city.Equals(other.city)
                && this.state.Equals(other.state)
                && this.zip.Equals(other.zip));
        }
    }
 }

现在,如果我不实现接口,离开: IEquatable<Address>的代码,似乎应用程序的操作完全相同。因此,我不清楚为什么要实现这个接口?我可以编写自己的自定义Equals方法,而不需要它,断点仍然会击中方法并返回相同的结果。有人能帮我多解释一下吗?我挂断了为什么包括"IEquatable<Address>"之前调用Equals方法。

为什么要实施公平教育?接口

现在,如果我不实现接口,并在代码中留下:IEquatable,看起来应用程序的操作完全相同。

嗯,这取决于"应用程序"做什么。例如:

List<Address> addresses = new List<Address>
{
    new Address { ... }
};
int index = addresses.IndexOf(new Address { ... });

…这将不起作用(即index将是-1),如果你既没有覆盖Equals(object)也没有实现IEquatable<T>List<T>.IndexOf不会调用你的Equals重载。

代码知道你的特定的类将拾取Equals过载-但任何代码(例如泛型集合,所有的LINQ到对象等),只与任意对象工作将不会拾取它。

.NET框架有许多令人困惑的等式检查的可能性:

  1. 虚拟Object.Equals(object)
  2. 可重载相等运算符(==, !=, <=, >=)
  3. IEquatable<T>.Equals(T)
  4. IComparable.CompareTo(object)
  5. IComparable<T>.CompareTo(T)
  6. IEqualityComparer.Equals(object, object)
  7. IEqualityComparer<T>.Equals(T, T)
  8. IComparer.Compare(object, object)
  9. IComparer<T>.Compare(T, T)

我没有提到ReferenceEquals,静态Object.Equals(object, object)和特殊情况(例如。字符串和浮点比较),只是在我们可以实现某些东西的情况下。

另外,对于结构和类,前两点的默认行为是不同的。因此,用户对实现什么以及如何实现感到困惑也就不足为奇了。

一般来说,您可以遵循以下模式:

<标题>
  • 默认情况下,Equals(object)方法和相等运算符(==!=)都检查引用是否相等
  • 如果引用相等不适合你,覆盖Equals方法(也覆盖GetHashCode;否则,您的类将无法在散列集合中使用)
  • 您可以保留==!=操作符的原始引用相等功能,这在类中很常见。但是如果你重载它们,它必须与Equals一致。
  • 如果您的实例可以在更少或更大的意义上相互比较,则实现IComparable接口。当Equals报告相等时,CompareTo必须返回0(同样是一致性)。

基本上就是这样。为类实现泛型IEquatable<T>Comparable<T>接口并不是必须的:因为没有装箱,所以在泛型集合中性能增益将是最小的。但是记住,如果你实现它们,保持一致性

<标题>结构h1> li>默认情况下,Equals(object)对结构体执行值比较(检查字段值)。虽然这通常是值类型的预期行为,但基本实现通过使用反射来实现这一点,这具有糟糕的性能。所以一定要在公共结构体中重写Equals(object),即使你实现了与原来相同的功能。
  • Equals(object)方法用于结构体时,会发生装箱,这有性能成本(不如ValueType.Equals中的反射那么糟糕,但这很重要)。这就是IEquatable<T>接口存在的原因。如果要在泛型集合中使用结构,则应该在结构上实现它。我说过要保持一致性吗?
  • 默认情况下,==!=操作符不能用于结构体,所以如果想使用它们,必须重载它们。只需调用强类型的IEquatable<T>.Equals(T)实现。
  • 与类类似,如果less或greater对您的类型有意义,则实现IComparable接口。在结构体的情况下,你应该实现IComparable<T>以及使事情的性能(例如。Array.Sort, List<T>.BinarySearch,使用类型作为SortedList<TKey, TValue>中的键,等等)。如果你重载了==, !=操作符,你也应该重载<, >, <=, >=
  • 一个小补充:如果您必须使用具有不适当的比较逻辑的类型来满足您的需要,则可以使用6中的接口。到9。在列表中。这是您可以忘记一致性的地方(至少考虑到类型的self Equals),您可以实现可用于基于哈希和排序的集合的自定义比较。

    如果您已经覆盖了Equals(object obj)方法,那么这将只是性能问题,正如这里所指出的:IEquatable和仅仅覆盖Object.Equals()之间的区别是什么?

    但是只要你没有重写Equals(object obj),而是提供了你自己的强类型Equals(Adddress obj)方法,没有实现IEquatable<T>,你没有告诉所有依赖于这个接口实现来操作比较的类,你有自己的Equals方法应该使用

    因此,正如John Skeet所指出的,List<Address>.IndexOf用于比较地址的EqualityComparer<Address>.Default属性将无法知道它应该使用Equals方法。

    IEquatable接口只是用我们在泛型参数中提供的任何类型添加Equals方法。然后函数重载处理剩余部分。

    如果在Employee结构中添加等价对象,则该对象可以与Employee对象进行比较,而无需进行类型转换。虽然我们也可以用默认的Equals方法来实现,它接受Object作为参数,所以从对象到结构的转换涉及到装箱。因此,有了平等的"雇员"。将提高性能。

    例如,

    假设我们想比较Employee结构与另一个Employee

    if(e1.Equals(e2))
    {
       //do some
    }
    

    对于上面的例子,它将使用Employee作为参数的Equals。因此不需要装箱或拆箱

     struct Employee : IEquatable<Employee>
    {
        public int Id { get; set; }
        public bool Equals(Employee other)
        {
            //no boxing not unboxing, direct compare
            return this.Id == other.Id;
        }
        public override bool Equals(object obj)
        {
            if(obj is Employee)
            {   //un boxing
                return ((Employee)obj).Id==this.Id;
            }
            return base.Equals(obj);
        }
    }
    

    更多的例子:

    Int结构实现了可等价的

    Bool结构实现了等价的

    Float结构实现了

    如果你调用someint。Equals(1)它不会触发Equals(object)方法。它触发Equals(int)方法