C# -IComparable<T> and IEquatable<T>

3
3个回答

9

IComparable 定义了顺序(小于、大于)。它定义的方法是 CompareTo,通过它可以确定两个元素之间的顺序。

IEquatable 定义了相等性。它定义的方法是 Equals,它可以让您确定两个元素是否相等。

比较示例,按年龄对 Person 进行排序:

public class Person : IComparable<Person>
{
    public int Age { get; set; }
    public int ID { get; set; }

    public int CompareTo(Person other)
    {

        return Math.Sign(Age - other.Age); // -1 other greater than this
                                           // 0 if same age
                                           // 1 if this greater than other
    }
}

排序用法:

[Test]
public void SortTest()
{
    var persons = new List<Person>
                      {
                          new Person { Age = 0 },
                          new Person { Age = 2 },
                          new Person { Age = 1 }
                      };

    persons.Sort();

    Assert.AreEqual(0, persons[0].Age);
    Assert.AreEqual(1, persons[1].Age);
    Assert.AreEqual(2, persons[2].Age);
}

用ID识别个人的相等性示例:

public class Person : IEquatable<Person>
{
    public int Age { get; set; }
    public int ID { get; set; }

    public bool Equals(Person other)
    {
        return ID == other.ID;
    }
}

你可以通过重载运算符<等来实现。但是请记住,不是所有的.NET语言(例如VB.Net)都支持运算符重载,这就是为什么框架不能依赖它的原因。此外,拥有一个接口允许您将对象传递给任何接受该接口的方法。不知道您的类型的方法无法知道它是否已经重载了任何运算符。 - shf301
使用 Math.Sign 实现 CompareTo 是非常糟糕的。溢出/下溢 FTW。 - Paul Groke

2

如果您正在对 IEnumerable<T> 进行排序,如果要比较两个实例的相等性,请使用 IComparable<T>;如果要比较两个实例是否相等,则使用 IEquatable<T>


1
通常,任何排序功能都会使用您的类的IComparable接口(如果可用),否则.Net将应用默认排序,这可能完全出乎意料。
如果您不定义一个,则将使用默认值 - 在您继承自某个实现了IComparable的东西的情况下,如果某个基类实现了这个,则排序顺序将是基类定义的任何内容。 IEquatable定义了相等性,并允许您使用Equals方法定义.Net如何确定您的类的实例是否相等。如果您没有定义一个,则默认情况下基于引用相等性进行相等性比较。这意味着除非您在比较指向同一类实例的两个引用,否则它们不相等,即使您期望它们相等。同样,如果您继承自一个实现了该接口的基类,并且在您的类中未实现它,则将使用基类的相等性计算。
通常,如果您要与常见的.Net函数一起使用它们,则实现这些功能非常重要。例如,如果您在您的类的集合上使用Contains()函数,则它将尝试使用IEquatable接口。
来自MSDN:
IEquatable<(Of <(T)>)>接口用于泛型集合对象,例如Dictionary<(Of )>、List<(Of )>和LinkedList<(Of )>等,在Contains、IndexOf、LastIndexOf和Remove等方法中测试相等性。任何可能存储在泛型集合中的对象都应该实现它。
IComparable<(Of <(T)>)>接口为泛型集合对象的成员提供了强类型比较方法。因此,通常不会直接从开发人员代码中调用它。相反,它会被像List<(Of )>..::.Sort()()()和Add这样的方法自动调用。

.


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接