Dalam C #, dapatkah suatu kelas mewarisi dari kelas lain dan suatu antarmuka?

130

Saya ingin tahu apakah suatu kelas dapat mewarisi dari kelas dan antarmuka. Contoh kode di bawah ini tidak berfungsi, tetapi saya pikir itu menyampaikan apa yang ingin saya lakukan. Alasan saya ingin melakukan ini adalah karena di perusahaan saya, kami membuat perangkat USB, serial, Ethernet, dll. Saya mencoba mengembangkan komponen / antarmuka umum yang dapat saya gunakan untuk menulis program untuk semua perangkat kami yang akan membantu menjaga hal-hal umum (seperti menyambungkan, memutuskan sambungan, mendapatkan firmware) sama untuk semua aplikasi kami.

Untuk menambah pertanyaan ini: Jika GenericDevice berada dalam proyek yang berbeda, dapatkah saya menempatkan antarmuka IOurDevices dalam proyek itu kemudian membuat kelas USBDevice mengimplementasikan antarmuka jika saya menambahkan referensi ke proyek pertama? Karena ingin hanya merujuk satu proyek dan kemudian mengimplementasikan antarmuka yang berbeda tergantung pada perangkat apa.

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;
   }
}
PICYourBrain
sumber
5
Untuk referensi Anda di masa mendatang, bagian 10.1.4 dari spesifikasi C # menjelaskan dengan tepat bagaimana mendeklarasikan kelas yang memiliki beberapa tipe dasar.
Eric Lippert
@ Eric Lippert: Bisakah Anda membantu saya untuk memahami tentang kasus ini apakah cara yang benar dan akan tersedia di masa depan?
Gul Md Irsyad

Jawaban:

246

Iya. Mencoba:

class USBDevice : GenericDevice, IOurDevice

Catatan: Kelas dasar harus ada sebelum daftar nama antarmuka.

Tentu saja, Anda masih perlu mengimplementasikan semua anggota yang didefinisikan oleh antarmuka. Namun, jika kelas dasar berisi anggota yang cocok dengan anggota antarmuka, anggota kelas dasar dapat berfungsi sebagai implementasi anggota antarmuka dan Anda tidak diharuskan untuk mengimplementasikannya lagi secara manual.

Mehrdad Afshari
sumber
1
Yap ini berhasil! Kenapa aku tidak memikirkan itu! Dan untuk komentar di bawah ini. Terima kasih telah menjelaskan kepada saya tentang hal itu (Kelas tidak mewarisi antarmuka, antarmuka IMPLEMENT)
PICyourBrain
1
@Jordan, juga perhatikan bahwa kelas dasar dan daftar antarmuka yang diwarisi dipisahkan oleh koma setelah titik dua awal (@ Mehrdad's example).
JMD
1
untuk memperluas sedikit: jika kelas dasar Anda mengimplementasikan antarmuka maka kelas turunan Anda secara otomatis mengimplementasikan antarmuka itu - bahkan tanpa USBDevice : IOurDevice. Menambahkan implementasi secara eksplisit tidak berdampak pada kelas dasar, tetapi dapat membantu memberikan penekanan pada antarmuka.
STW
1
@ David, sementara Anda tidak salah, itu bukan terminologi yang mencegah kode @ Jordan bekerja. Itu sintaks yang salah.
JMD
2
+1 untuk juga menjernihkan pertanyaan yang ingin saya tanyakan mengenai anggota yang identik di Pangkalan dan Antarmuka.
Riegardt Steyn
21

Tidak, tidak juga. Tapi itu bisa mewarisi dari kelas dan mengimplementasikan satu atau lebih antarmuka.

Terminologi yang jelas penting ketika membahas konsep-konsep seperti ini. Salah satu hal yang akan Anda lihat menandai tulisan Jon Skeet, misalnya, baik di sini maupun di media cetak, adalah bahwa ia selalu tepat dalam cara ia mendeskripsikan sesuatu.

David M.
sumber
8
Atau Eric Lippert, yang tulisannya sangat akurat.
Mathias
21

Tidak terkait dengan pertanyaan (jawaban Mehrdad seharusnya membuat Anda pergi), dan saya harap ini tidak dianggap sebagai nitpicky: kelas tidak mewarisi antarmuka, mereka mengimplementasikannya .

.NET tidak mendukung multiple-inheritance, jadi menjaga persyaratan tetap lurus dapat membantu dalam komunikasi. Kelas dapat mewarisi dari satu superclass dan dapat mengimplementasikan sebanyak mungkin antarmuka yang diinginkan.


Menanggapi komentar Eric ... Saya berdiskusi dengan pengembang lain tentang apakah antarmuka "mewarisi", "mengimplementasikan", "mengharuskan", atau "membawa" antarmuka dengan deklarasi seperti:

public interface ITwo : IOne

Jawaban teknisnya adalah karena ITwomewarisi IOnebeberapa alasan:

  • Antarmuka tidak pernah memiliki implementasi, jadi berargumen bahwa ITwo implementasinya IOne salah
  • ITwomewarisi IOnemetode, jika MethodOne()ada IOnemaka itu juga dapat diakses dari ITwo. yaitu: ((ITwo)someObject).MethodOne())valid, meskipun ITwotidak secara eksplisit mengandung definisi untukMethodOne()
  • ... karena runtime bilang begitu! typeof(IOne).IsAssignableFrom(typeof(ITwo))kembalitrue

Kami akhirnya setuju bahwa antarmuka mendukung pewarisan sejati / penuh. Fitur warisan yang hilang (seperti penggantian, abstrak / virtual accessors, dll) hilang dari antarmuka, bukan dari warisan antarmuka. Itu masih tidak membuat konsepnya sederhana atau jelas, tetapi membantu memahami apa yang sebenarnya terjadi di balik tudung di dunia Eric :-)

STW
sumber
3
Meskipun, sayangnya, antarmuka mewarisi antarmuka lain. Saya menemukan pilihan kata-kata itu tidak menguntungkan, tetapi kita terjebak dengan itu sekarang. Saya lebih suka menganggap antarmuka sebagai membutuhkan antarmuka lain. Yaitu, ketika Anda mengatakan "antarmuka IFoo: IBar" itu berarti "seorang pelaksana IFoo juga diperlukan untuk mengimplementasikan IBar".
Eric Lippert
@ Eric Saya setuju ini istilah yang tidak jelas dan memperdebatkannya dengan seorang kolega beberapa waktu lalu. Pada akhirnya kami memutuskan bahwa mengatakan "ITwo mewarisi IOne". Saya akan memperbarui jawaban saya dengan beberapa alasan kecil (hanya karena mereka tidak akan cocok dengan jelas dalam komentar).
STW
Tentu; jika Anda mendefinisikan "A inherit from B" sebagai makna "anggota B adalah semua anggota A", maka interface melakukan "inherit" dari antarmuka dasar. Ini adalah definisi yang masuk akal. Tapi saya lebih suka menganggap "warisan" sebagai lebih ketat tentang tidak hanya berbagi anggota yang abstrak dan tidak diimplementasikan, tetapi juga tentang mewarisi implementasi . Karena antarmuka tidak memiliki implementasi, saya merasa agak khawatir untuk menganggap antarmuka sebagai warisan dari apa pun. Ini adalah hal yang halus dan dapat diperdebatkan.
Eric Lippert
Istilah lain yang saya suka adalah "memperpanjang". Jadi Anda dapat membaca "antarmuka IFoo: IBar" yang berarti bahwa IFoo memperluas persyaratan IBar.
jasonh
1
@ Joan: Anda benar bahwa kelas mengimplementasikan (dan tidak dapat mewarisi) antarmuka. Maksud Eric adalah bahwa antarmuka dapat mewarisi antarmuka lain - yang bisa agak sulit dicerna mengingat bahwa antarmuka hanya "spesifikasi" daripada implementasi.
STW
1

Saya menemukan jawaban untuk bagian kedua dari pertanyaan saya. Ya, sebuah kelas dapat mengimplementasikan antarmuka yang ada di kelas yang berbeda selama antarmuka tersebut dinyatakan sebagai publik.

PICYourBrain
sumber
Tidak harus publik dalam semua kasus. Hanya dapat diakses. Sebagai contoh class ContainsAll { private interface INested { /* ... */ } private class MyExample : INested { /* ... */ } }, MyExamplekelas mengimplementasikan antarmuka pribadi bersarang. Dalam contoh lain, antarmuka bersarang (dan kelas yang mengandung) bisa menjadi internal. Itu semua tergantung pada siapa yang perlu menggunakannya dan peduli dengan mereka.
Jeppe Stig Nielsen