Sebagai contoh, misalkan saya ingin ICar
antarmuka dan bahwa semua implementasi akan berisi bidang Year
. Apakah ini berarti bahwa setiap implementasi harus secara terpisah menyatakan Year
? Bukankah lebih baik mendefinisikannya di antarmuka saja?
223
Jawaban:
Meskipun banyak jawaban lain yang benar di tingkat semantik, saya merasa menarik untuk juga mendekati pertanyaan-pertanyaan semacam ini dari tingkat rincian implementasi.
Antarmuka dapat dianggap sebagai kumpulan slot , yang berisi metode . Ketika sebuah kelas mengimplementasikan sebuah antarmuka, kelas tersebut diperlukan untuk memberi tahu runtime bagaimana mengisi semua slot yang diperlukan. Kapan kamu berkata
kelas mengatakan "ketika Anda membuat instance dari saya, isikan referensi untuk Foo.M di slot untuk IFoo.M.
Kemudian saat Anda melakukan panggilan:
kompiler menghasilkan kode yang mengatakan "tanyakan objek metode apa yang ada di slot untuk IFoo.M, dan panggil metode itu.
Jika sebuah antarmuka adalah kumpulan slot yang berisi metode, maka beberapa slot itu juga bisa berisi metode get and set dari properti, metode get and set dari pengindeks, dan metode tambah dan hapus acara. Tapi lapangan bukan metode . Tidak ada "slot" yang terkait dengan bidang yang dapat Anda "isi" dengan referensi ke lokasi bidang. Dan karena itu, antarmuka dapat mendefinisikan metode, properti, pengindeks dan peristiwa, tetapi tidak bidang.
sumber
An interface cannot contain constants, fields, operators
Dari. msdn.microsoft.com/en-us/library/ms173156.aspx )int One()
, maka implementasinyapublic int One(){return 1;}
bukan bidang.Antarmuka dalam C # dimaksudkan untuk mendefinisikan kontrak yang akan dipatuhi suatu kelas - bukan implementasi tertentu.
Dalam semangat itu, antarmuka C # memang memungkinkan properti untuk didefinisikan - yang pemanggil harus menyediakan implementasi untuk:
Kelas implementasi dapat menggunakan properti otomatis untuk menyederhanakan implementasi, jika tidak ada logika khusus yang terkait dengan properti:
sumber
Year
?public int Year => 123;
. Namun, dalam hal ini tidak masuk akal untuk memiliki setter, sehingga antarmuka harus didefinisikan denganint Year { get; }
Nyatakan sebagai properti:
sumber
Eric Lippert memakukannya, saya akan menggunakan cara yang berbeda untuk mengatakan apa yang dia katakan. Semua anggota antarmuka adalah virtual dan mereka semua harus ditimpa oleh kelas yang mewarisi antarmuka. Anda tidak secara eksplisit menulis kata kunci virtual dalam deklarasi antarmuka, atau menggunakan kata kunci override di kelas, mereka tersirat.
Kata kunci virtual diimplementasikan dalam .NET dengan metode dan apa yang disebut v-table, sebuah array dari pointer metode. Kata kunci override mengisi slot v-table dengan pointer metode yang berbeda, menimpa yang diproduksi oleh kelas dasar. Properti, acara, dan pengindeks diimplementasikan sebagai metode di bawah tenda. Tapi ladang tidak. Antarmuka karena itu tidak dapat berisi bidang.
sumber
Mengapa tidak hanya memiliki
Year
properti, yang tidak apa-apa?Antarmuka tidak berisi bidang karena bidang mewakili implementasi representasi data yang spesifik, dan mengeksposnya akan memecah enkapsulasi. Dengan demikian memiliki antarmuka dengan bidang secara efektif akan menjadi pengkodean untuk implementasi, bukan antarmuka, yang merupakan paradoks penasaran untuk memiliki antarmuka!
Misalnya, bagian dari
Year
spesifikasi Anda mungkin mengharuskanICar
pelaksana tidak valid untuk mengizinkan penugasanYear
yang lebih lambat dari tahun berjalan +1 atau sebelum 1900. Tidak ada cara untuk mengatakan bahwa jika Anda telah membukaYear
bidang - jauh lebih baik menggunakan properti bukan untuk melakukan pekerjaan di sini.sumber
Jawaban singkatnya adalah ya, setiap jenis implementasi harus membuat variabel pendukungnya sendiri. Ini karena antarmuka analog dengan kontrak. Yang dapat dilakukan hanyalah menentukan bagian kode yang dapat diakses publik yang harus tersedia oleh suatu tipe implementasi; itu tidak dapat berisi kode apa pun itu sendiri.
Pertimbangkan skenario ini menggunakan apa yang Anda sarankan:
Kami memiliki beberapa masalah di sini:
myBackingVariable
akanMyClass
digunakan?Pendekatan yang paling umum diambil adalah dengan mendeklarasikan antarmuka dan kelas abstrak barebones yang mengimplementasikannya. Ini memungkinkan Anda fleksibilitas untuk mewarisi dari kelas abstrak dan mendapatkan implementasi secara gratis, atau secara eksplisit mengimplementasikan antarmuka dan diizinkan untuk mewarisi dari kelas lain. Ini berfungsi seperti ini:
sumber
Orang lain telah memberikan 'Mengapa', jadi saya hanya akan menambahkan bahwa antarmuka Anda dapat mendefinisikan Kontrol; jika Anda membungkusnya di properti:
sumber
Antarmuka tidak mengandung implementasi apa pun.
sumber
Banyak yang sudah dikatakan, tetapi untuk membuatnya sederhana, ini pendapat saya. Antarmuka dimaksudkan untuk memiliki kontrak metode yang akan dilaksanakan oleh konsumen atau kelas dan tidak memiliki bidang untuk menyimpan nilai.
Anda mungkin berpendapat bahwa mengapa properti diperbolehkan? Jadi jawaban sederhananya adalah - properti didefinisikan secara internal sebagai metode saja.
sumber
Untuk ini, Anda dapat memiliki kelas dasar Mobil yang mengimplementasikan bidang tahun, dan semua implementasi lainnya dapat mewarisinya.
sumber
Antarmuka mendefinisikan properti instance publik dan metode. Bidang biasanya bersifat pribadi, atau paling banyak dilindungi, internal, atau internal terlindungi (istilah "bidang" biasanya tidak digunakan untuk apa pun yang publik).
Seperti yang dinyatakan oleh balasan lain Anda dapat mendefinisikan kelas dasar dan mendefinisikan properti yang dilindungi yang akan dapat diakses oleh semua pewaris.
Satu keanehan adalah bahwa suatu antarmuka sebenarnya dapat didefinisikan sebagai internal tetapi membatasi kegunaan antarmuka, dan biasanya digunakan untuk mendefinisikan fungsionalitas internal yang tidak digunakan oleh kode eksternal lainnya.
sumber