如何实现IComparable接口?


76

我用类的实例填充数组:

BankAccount[] a;
. . .

a = new BankAccount[]
{
    new BankAccount("George Smith", 500m),
    new BankAccount("Sid Zimmerman", 300m)
};

填充此数组后,我想按余额金额对其进行排序。为此,我希望能够使用检查每个元素是否可排序IComparable
我需要使用接口来做到这一点。到目前为止,我有以下代码:

public interface IComparable
{
    decimal CompareTo(BankAccount obj);
}

但是我不确定这是否是正确的解决方案。有什么建议吗?

Answers:


135

您不应该定义IComparable自己。已经定义。相反,您需要在您的课程上实现IComparableBankAccount

在定义的位置class BankAccount,确保它实现了IComparable接口。然后写BankAccount.CompareTo比较两个对象的余额。

public class BankAccount : IComparable<BankAccount>
{
    [...]

    public int CompareTo(BankAccount that)
    {
        if (this.Balance <  that.Balance) return -1;
        if (this.Balance == that.Balance) return 0;
        return 1;
    }
}

编辑以通过评论显示Jeffrey L Whitledge的解决方案:

public class BankAccount : IComparable<BankAccount>
{
    [...]

    public int CompareTo(BankAccount that)
    {
        return this.Balance.CompareTo(that.Balance);
    }
}

42
我喜欢return this.Balance.CompareTo(that.Balance);
Jeffrey L Whitledge 2010年

3
@我是一个女孩-我不确定你的意思。也许您不清楚我要替换的代码的哪一部分。我将所有这些内容放入评论中,然后:public class BankAccount : IComparable<BankAccount> { [...] int CompareTo(BankAccount that) { return this.Balance.CompareTo(that.Balance); } }更清楚了吗?
Jeffrey L Whitledge,2010年

5
另一种方式是return Balance - that.Balance;
fbiagi

7
在第一个版本中,应该this.Balance < that.Balance按余额递增的顺序进行排序。-1 =这个小于那个,0 =这个等于那个,1 =这个大于那个
Keith 2014年

5
return Balance - that.Balance如果天平接近其类型的极限,则不是一个好主意,因为溢出可能会给您带来错误的结果。例如,如果Balance是a short,并且this.Balance是32700且that.Balance是-100,则减法的结果将是-32736,而明显的的结果CompareTo应为正数。同样,如果Balance为a ushort,则减法的结果永远不会为负,这显然也是错误的。
詹姆斯

16

您要破坏性地对数组进行排序吗?也就是说,您是否要更改数组中各项的顺序?还是只需要特定顺序的商品清单,而又不破坏原始顺序?

我建议这样做几乎总是更好。考虑使用LINQ进行非破坏性排序。(并考虑使用比“ a”更有意义的变量名。)

BankAccount[] bankAccounts = { whatever };
var sortedByBalance = from bankAccount in bankAccounts 
                      orderby bankAccount.Balance 
                      select bankAccount;
Display(sortedByBalance);

我想通过实施icompare破坏它
Alex Gordon 2010年

8
@Lippert:虽然这是一个非常有效的响应,但是从讨论中看来,OP几乎不了解实现接口的含义。她可能尚未准备好回答您所提出的问题。
abelenky

嗨,埃里克,假设引用类型是null实现IComparable<T>和子类化的最佳做法是什么?它是否取决于用户情况还是通常最好抛出异常,因为实际的比较逻辑通常会转发给on的某些属性。Comparer<T>TT
stt106

1
@ stt106:听起来像个问题;考虑将其发布为问题。简短的答案:我将对所有可能的值(包括null)实施总订单。传统上,null小于所有其他可能性。也就是说,如果您认为提供null总是错误的,则抛出异常可能是明智的。
埃里克·利珀特

15

IComparable .NET中已经存在具有CompareTo的此定义

int CompareTo(Object obj)

您不应该创建接口-您应该实现它。

public class BankAccount : IComparable {

    int CompareTo(Object obj) {
           // return Less than zero if this object 
           // is less than the object specified by the CompareTo method.

           // return Zero if this object is equal to the object 
           // specified by the CompareTo method.

           // return Greater than zero if this object is greater than 
           // the object specified by the CompareTo method.
    }
}

1
抱歉,您能否举一个例子说明我将如何实施它
Alex Gordon

2
而且,如果obj是null或类型不是BankAccount怎么办?编辑:根据MSDN在这里:msdn.microsoft.com/en-us/library/…:抛出一个ArgumentException

10

一种替代方法是使用LINQ并完全跳过实现IComparable的方法:

BankAccount[] sorted = a.OrderBy(ba => ba.Balance).ToArray();

5

已经存在IComparable<T>,但您最好同时支持IComparable<T>IComparable。使用内置命令Comparer<T>.Default通常是一个更简单的选择。Array.Sort,例如,将接受此类比较器。


2

如果只需要对它们进行排序BankAccounts,请使用LINQ如下所示的内容

BankAccount[] a = new BankAccount[]
{
    new BankAccount("George Smith", 500m),
    new BankAccount("Sid Zimmerman", 300m)
};

a = a.OrderBy(bank => bank.Balance).ToArray();
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.