2010-01-13 60 views
111

Tôi muốn biết liệu một lớp học có thể kế thừa từ một lớp và một giao diện hay không. Mã ví dụ bên dưới không hiệu quả nhưng tôi nghĩ nó chuyển tải những gì tôi muốn làm. Lý do tôi muốn làm điều này là bởi vì tại công ty của tôi, chúng tôi tạo thiết bị USB, nối tiếp, Ethernet, v.v. Tôi đang cố gắng phát triển một thành phần/giao diện chung mà tôi có thể sử dụng để viết các chương trình cho tất cả các thiết bị sẽ giúp giữ cho mọi thứ phổ biến (như kết nối, ngắt kết nối, nhận firmware) cho tất cả các ứng dụng của chúng tôi.Trong C#, một lớp có thể kế thừa từ một lớp khác và một giao diện không?

Để thêm vào câu hỏi này: Nếu GenericDevice nằm trong dự án khác, tôi có thể đặt giao diện IOurDevices vào dự án đó sau đó làm cho lớp USBDevice triển khai giao diện nếu tôi thêm tham chiếu vào dự án đầu tiên? Bởi vì chỉ muốn tham khảo một dự án và sau đó thực hiện các giao diện khác nhau tùy thuộc vào thiết bị là gì.

class GenericDevice 
{ 
    private string _connectionState; 
    public connectionState 
    { 
     get{return _connectionState; } 
     set{ _connectionState = value;} 
    } 
} 

interface IOurDevices 
{ 
    void connectToDevice(); 
    void DisconnectDevice(); 
    void GetFirmwareVersion(); 
} 

class USBDevice : IOurDevices : GenericDevice 
{ 
    //here I would define the methods in the interface 
    //like this... 
    void connectToDevice() 
    { 
     connectionState = "connected"; 
    } 
} 

//so that in my main program I can do this... 

class myProgram 
{ 
    main() 
    { 
     USBDevice myUSB = new USBDevice(); 
     myUSB.ConnectToDevice; 
    } 
} 
+4

Để tham khảo trong tương lai, mục 10.1.4 của đặc tả C# mô tả chính xác cách khai báo một lớp có nhiều loại cơ sở. –

+0

@Eric Lippert: Bạn có thể giúp tôi hiểu về trường hợp này cho dù đó là cách chính xác và sẽ có sẵn trong tương lai không? –

Trả lời

210

Có. Hãy thử:

class USBDevice : GenericDevice, IOurDevice 

Lưu ý: lớp Các cơ sở nên đến trước khi danh sách các tên giao diện.

Tất nhiên, bạn vẫn cần thực hiện tất cả các thành viên mà giao diện xác định. Tuy nhiên, nếu lớp cơ sở chứa một thành viên phù hợp với một thành viên giao diện, thì thành viên của lớp cơ sở có thể hoạt động như việc thực hiện thành viên giao diện và bạn không cần thực hiện lại thủ công nó một lần nữa.

+1

Yup công trình này! Tại sao tôi không nghĩ về điều đó! Và nhận xét bên dưới. Cảm ơn bạn đã xóa tôi trên đó (Lớp không kế thừa giao diện, giao diện IMPLEMENT) – PICyourBrain

+1

@Jordan, cũng lưu ý rằng lớp cơ sở và danh sách giao diện được kế thừa được phân cách bằng dấu phẩy sau dấu hai chấm đầu tiên (ví dụ của @ Mehrdad) . – JMD

+1

để mở rộng một chút: nếu lớp cơ sở của bạn triển khai giao diện thì lớp dẫn xuất của bạn sẽ tự động triển khai giao diện đó - ngay cả khi không có 'USBDevice: IOurDevice'. Việc bổ sung việc triển khai một cách rõ ràng không ảnh hưởng đến lớp cơ sở, nhưng nó có thể giúp nhấn mạnh vào giao diện. – STW

18

Không, không chính xác. Nhưng nó có thể kế thừa từ một lớp và triển khai một hoặc nhiều giao diện.

Thuật ngữ rõ ràng là quan trọng khi thảo luận về các khái niệm như thế này. Một trong những điều mà bạn sẽ thấy đánh dấu của Jon Skeet bằng văn bản, ví dụ, cả ở đây và trong in ấn, là ông luôn luôn chính xác trong cách ông decribes mọi thứ.

+8

Hoặc Eric Lippert, người viết rất chính xác. – Mathias

16

Không liên quan đến câu hỏi (câu trả lời Mehrdad của sẽ giúp bạn đi), và tôi hy vọng điều này không được thực hiện như nitpicky: lớp học không kế thừa giao diện, họ thực hiện họ.

.NET không hỗ trợ đa thừa kế, vì vậy việc giữ các điều khoản liên tục có thể giúp liên lạc. Một lớp có thể kế thừa từ một siêu lớp và có thể triển khai bao nhiêu giao diện theo ý muốn.


Để trả lời nhận xét của Eric ...Tôi đã có một cuộc thảo luận với một nhà phát triển về việc có hay không giao diện "kế thừa", "thực hiện", "yêu cầu", hay "mang theo" giao diện với một khai báo như sau:

public interface ITwo : IOne 

Câu trả lời kỹ thuật là ITwo không kế thừa IOne cho một vài lý do:

  • Giao diện bao giờ có một thực hiện, vì vậy cho rằng ITwothực hiệnIOne là fl tại sai
  • ITwo kế thừa IOne phương pháp, nếu MethodOne() tồn tại trên IOne thì nó cũng có thể truy cập từ ITwo. tức là: ((ITwo)someObject).MethodOne()) hợp lệ, mặc dù ITwo không chứa định nghĩa rõ ràng cho MethodOne()
  • ... vì thời gian chạy nói như vậy! typeof(IOne).IsAssignableFrom(typeof(ITwo)) trả về true

Cuối cùng, chúng tôi đã đồng ý rằng giao diện hỗ trợ kế thừa thực sự/đầy đủ. Các tính năng thừa kế bị thiếu (chẳng hạn như ghi đè, các trình truy cập trừu tượng/ảo, vv) bị thiếu trong các giao diện, không phải từ giao tiếp thừa kế. Nó vẫn không làm cho khái niệm đơn giản hay rõ ràng, nhưng nó giúp hiểu những gì thực sự xảy ra dưới mui xe trong thế giới của Eric :-)

+2

Mặc dù, thật không may, giao diện * kế thừa * các giao diện khác. Tôi thấy rằng sự lựa chọn của các từ không may, nhưng chúng tôi đang mắc kẹt với nó bây giờ. Tôi thích nghĩ về các giao diện như * yêu cầu * các giao diện khác.Tức là, khi bạn nói "giao diện IFoo: IBar" có nghĩa là "một người triển khai IFoo được yêu cầu cũng phải thực hiện IBar". –

+0

@Eric Tôi đồng ý rằng đó là một thuật ngữ không rõ ràng và tranh luận với một đồng nghiệp trong khi trở lại. Cuối cùng, chúng tôi quyết định nói rằng "ITwo kế thừa IOne". Tôi sẽ cập nhật câu trả lời của tôi với một vài lý do nhỏ (chỉ vì họ sẽ không phù hợp rõ ràng trong một bình luận). – STW

+0

Chắc chắn; nếu bạn định nghĩa "Một thừa kế từ B" là "các thành viên của B là tất cả các thành viên của A", thì các giao diện làm "kế thừa" từ các giao diện cơ bản. Đây là một định nghĩa hợp lý. Nhưng tôi thích nghĩ về "sự thừa kế" càng nghiêm túc hơn về việc không chỉ chia sẻ các thành viên trừu tượng, chưa thực hiện, mà đúng hơn, là về việc thừa kế * triển khai *. Vì các giao diện không có triển khai thực hiện, tôi thấy nó hơi khó chịu khi nghĩ về các giao diện như kế thừa từ bất cứ thứ gì. Đó là một điểm tinh tế và gây tranh cãi. –

1

Tôi tìm thấy câu trả lời cho phần thứ hai của câu hỏi. Có, một lớp có thể triển khai một giao diện nằm trong một lớp khác miễn là giao diện được khai báo là công khai.

+0

Nó không phải công khai trong mọi trường hợp. Chỉ cần truy cập. Ví dụ 'class ContainsAll {private interface INested {/ * ... * /} lớp riêng MyExample: INested {/ * ... * /}}', lớp 'MyExample' thực hiện một giao diện riêng lồng nhau. Trong các ví dụ khác, giao diện lồng nhau (và lớp chứa) có thể là 'nội bộ'. Tất cả phụ thuộc vào ai cần sử dụng chúng và bận tâm với họ. –

Các vấn đề liên quan