Làm thế nào để triển khai giao diện IComp so sánh được?


78

Tôi đang điền một mảng với các phiên bản của một lớp:

BankAccount[] a;
. . .

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

Khi tôi điền mảng này, tôi muốn sắp xếp nó theo số dư. Để làm điều đó, tôi muốn có thể kiểm tra xem mỗi phần tử có thể sắp xếp bằng cách sử dụng hay không IComparable.
Tôi cần làm điều này bằng cách sử dụng giao diện. Cho đến nay tôi có mã sau:

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

Nhưng tôi không chắc liệu đây có phải là giải pháp phù hợp hay không. Có lời khuyên nào không?

Câu trả lời:


138

Bạn không nên IComparabletự định nghĩa . Nó đã được xác định. Thay vào đó, bạn cần phải triển khai IComparable trên BankAccountlớp của mình .

Nơi bạn đã xác định class BankAccount, hãy đảm bảo rằng nó triển khai IComparablegiao diện. Sau đó viết BankAccount.CompareTođể so sánh số dư của hai đối tượng.

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;
    }
}

Chỉnh sửa để hiển thị giải pháp của Jeffrey L Whitledge từ các nhận xét:

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

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

42
Tôi thíchreturn this.Balance.CompareTo(that.Balance);
Jeffrey L Whitledge,

3
@ tôi là một cô gái - Tôi không chắc bạn muốn nói gì. Có lẽ bạn không rõ tôi đã thay thế phần nào của mã. Tôi sẽ đưa tất cả vào bình luận, sau đó: public class BankAccount : IComparable<BankAccount> { [...] int CompareTo(BankAccount that) { return this.Balance.CompareTo(that.Balance); } }Điều đó rõ ràng hơn phải không?
Jeffrey L Whitledge,

5
Một cách khác sẽ làreturn Balance - that.Balance;
fbiagi

7
Trong phiên bản đầu tiên, nó phải được this.Balance < that.Balancesắp xếp theo số dư tăng dần. -1 = này là ít hơn thế, 0 = đây là tương đương với đó, 1 = đây là lớn hơn
Keith

5
return Balance - that.Balancekhông phải là một ý kiến ​​hay nếu số dư gần đến giới hạn của loại của nó, vì tràn có thể cho bạn kết quả sai. Ví dụ: nếu Số dư là a short, và this.Balancelà 32700 và that.Balancelà -100, kết quả của phép trừ sẽ là -32736, khi rõ ràng kết quả của CompareTophải là một số dương. Tương tự, nếu Số dư là a ushort, kết quả của phép trừ không bao giờ có thể âm, điều này cũng sai rõ ràng.
James

17

Bạn có muốn sắp xếp theo kiểu triệt tiêu mảng không? Đó là, bạn có muốn thực sự thay đổi thứ tự của các mục trong mảng không? Hay bạn chỉ muốn có một danh sách các mục theo một thứ tự cụ thể mà không hủy bỏ thứ tự ban đầu?

Tôi đề nghị rằng hầu như luôn luôn tốt hơn nếu làm điều sau. Cân nhắc sử dụng LINQ để đặt hàng không phá hủy. (Và hãy cân nhắc sử dụng tên biến có ý nghĩa hơn "a".)

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

tôi muốn hủy nó thực hiện icompare
Alex Gordon

8
@Lippert: Mặc dù đây là một phản hồi rất hợp lệ, nhưng có vẻ như từ cuộc thảo luận rằng OP hầu như không hiểu ý nghĩa của việc triển khai một giao diện. Có lẽ cô ấy vẫn chưa sẵn sàng cho mức độ câu hỏi mà bạn đang hỏi.
abelenky

Xin chào Eric, thực tiễn tốt nhất để xử lý nullkhi triển khai IComparable<T>và phân lớp Comparer<T>giả sử Tlà một loại tham chiếu là gì? Nó phụ thuộc vào trường hợp người dùng hay tốt hơn là ném ngoại lệ vì logic so sánh thực thường được chuyển tiếp đến một số thuộc tính trên T.
stt106

1
@ stt106: Nghe giống câu hỏi quá; xem xét đăng nó như một câu hỏi. Câu trả lời ngắn gọn: Tôi sẽ thực hiện một đơn đặt hàng tổng trên tất cả các giá trị có thể có, bao gồm cả null. Theo truyền thống, null nhỏ hơn tất cả các khả năng khác. Điều đó nói rằng, có thể hợp lý khi ném một ngoại lệ nếu bạn nghĩ rằng việc cung cấp giá trị null luôn là sai .
Eric Lippert

15

IComparable đã tồn tại trong .NET với định nghĩa này của CompareTo

int CompareTo(Object obj)

Bạn không phải tạo giao diện - bạn phải triển khai nó.

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
im xin lỗi u có thể cho tôi một ví dụ về làm thế nào tôi sẽ thực hiện nó
Alex Gordon

2
Và điều gì sẽ xảy ra nếu obj là nullhoặc thuộc loại khác BankAccount? CHỈNH SỬA: Theo MSDN tại đây: msdn.microsoft.com/en-us/library/… : ném an ArgumentException.
Ray

11

Một giải pháp thay thế là sử dụng LINQ và bỏ qua hoàn toàn việc triển khai ICompABLE:

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

6

Đã có IComparable<T>, nhưng lý tưởng nhất là bạn nên hỗ trợ cả hai IComparable<T>IComparable. Sử dụng bản sẵn có Comparer<T>.Defaultthường là một lựa chọn dễ dàng hơn. Array.Sort, ví dụ, sẽ chấp nhận một trình so sánh như vậy.


2

Nếu bạn chỉ cần sắp xếp những thứ này BankAccounts, hãy sử dụng LINQnhư sau

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

a = a.OrderBy(bank => bank.Balance).ToArray();
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.