C #: Kelas abstrak perlu mengimplementasikan antarmuka?

131

Kode pengujian saya dalam C #:

namespace DSnA
{
    public abstract class Test : IComparable
    {

    }
}

Hasil dalam kesalahan kompilator berikut:

error CS0535: 'DSnA.Test' does not implement interface member
'System.IComparable.CompareTo(object)'

Karena kelas Testadalah kelas abstrak , mengapa kompiler memerlukannya untuk mengimplementasikan antarmuka? Tidakkah persyaratan ini hanya wajib untuk kelas beton?

bguiz
sumber
Ha ha. Saya menulis satu hal kemudian memutuskan untuk mengubahnya. Maaf. :)
Joel
2
Berdasarkan downvotes dan komentar pada jawaban yang diterima, saya percaya downvotes datang karena cara pertanyaan tersebut diucapkan. OP bertanya "mengapa begini", yang akan berada di luar lingkup stackoverflow. Setelah menemukan ini sendiri, pertanyaannya lebih seperti "Apakah saya kehilangan sesuatu? Apakah saya benar-benar harus menyediakan implementasi? Apakah itu tidak mengalahkan titik itu menjadi kelas abstrak?" Yang jawabannya adalah "Tidak, Anda tidak harus menyediakan implementasi (yang akan melanggar tujuan kelas abstrak), tetapi inilah yang harus Anda lakukan, untuk membuat situasi Anda berhasil."
ToolmakerSteve
Saya menemukan kasus di mana Anda harus menyediakan implementasi. Di sinilah antarmuka memiliki parameter opsional. Jika Anda menyertakan metode sebagai abstrak di kelas dasar maka kelas-kelas yang diwarisi tidak akan dikompilasi tanpa parameter opsional (yang mengalahkan tujuan parameter opsional). Saya hanya melempar NotImplementedException dalam kasus ini.
Paul McCarthy
Abaikan komentar saya sebelumnya - itu tidak berfungsi seperti yang diharapkan, prinsip kejutan paling tidak berlaku di sini.
Paul McCarthy

Jawaban:

141

Di C #, kelas yang mengimplementasikan antarmuka diperlukan untuk mendefinisikan semua anggota antarmuka itu. Dalam kasus kelas abstrak, Anda cukup mendefinisikan anggota tersebut dengan abstractkata kunci:

interface IFoo
{
    void Bar();
}

abstract class Foo : IFoo
{
    public abstract void Bar();
}

Atau dengan kata lain: Anda tidak harus "menerapkan" itu (yang akan menjadi batasan yang mengerikan pada kelas abstrak); namun, dalam C #, Anda harus memberi tahu kompiler bahwa Anda dengan sengaja menyerahkan uang kepada subkelas beton - dan baris kode di atas menunjukkan cara melakukannya.

Komentar dan downvotes mengeluh bahwa ini bukan jawaban atas pertanyaan yang tidak tepat. Seseorang yang datang ke Stack Overflow, setelah menerima kesalahan kompilator ini, tetapi memiliki kelas abstrak di mana itu akan menjadi kesalahan untuk memasok implementasi, terjebak tanpa solusi yang baik - harus menulis metode implementasi yang melempar pengecualian runtime, sebuah karya yang menghebohkan. -around - sampai mereka memiliki informasi di atas. Baik atau buruknya C # membutuhkan saksi ini di luar lingkup Stack Overflow, dan tidak relevan dengan pertanyaan atau jawaban ini.

Joel
sumber
2
@ Ben Hanya melihat komentar Anda. Anda mungkin sudah menemukan jawabannya, tetapi kalau-kalau ada orang lain yang membutuhkannya. Lihat Implementasi Antarmuka Eksplisit: msdn.microsoft.com/en-us/library/ms173157.aspx
Joel
2
@ Joel @ Ben Saya tidak berpikir antarmuka eksplisit dapat bekerja dengan kelas abstrak. Dalam kode contoh di atas, ubah definisi Foomenjadi public abstract void IFoo.Bar();dan Anda mendapat keluhan bahwa "publik" dan "abstrak" bukan pengubah yang valid.
Darren Cook
8
Ini tidak menjawab pertanyaan mengapa ini bahkan diperlukan sama sekali, mengingat ini adalah kelas abstrak dan kompiler harus tahu cara mengisi bagian yang kosong. Di Jawa ini tidak perlu, yang memungkinkan untuk beberapa pola yang berguna seperti pola dekorator pada wadah ioc misalnya Spring / JavaEE (ketika Anda perlu menghias metode tertentu dari antarmuka yang dikelola). Implementasi yang sama in.net harus memaksa pengembang untuk menjadi sangat bertele-tele terutama pada antarmuka besar seperti ISSI nhibernate
Sheepy
1
Mixins AspectJ adalah contoh lain. Ini memungkinkan Anda untuk mencampur implementasi parsial dari banyak kelas abstrak menjadi satu antarmuka. Setiap kelas abstrak hanya perlu mengimplementasikan metode yang ingin diimplementasikan. Tidak ada metode abstrak bodoh boilerplate menghalangi seperti halnya jika saya membuat ulang fungsionalitas yang sama di .net
Sheepy
1
@ Sheepy - Benar, tapi, IMHO, Anda salah paham apa yang penanya butuhkan , dan bagaimana ini, memang, merupakan "jawaban". Saya juga memiliki pertanyaan yang sama - karena tidak masuk akal untuk diminta untuk memasok implementasi, jadi saya mandek. Jawabannya adalah: Anda tidak harus " mengimplementasikan " - tetapi inilah yang harus Anda lakukan untuk memberi tahu kompiler bahwa Anda tidak akan mengimplementasikannya. (Pertanyaan yang Anda [benar] katakan ini bukan jawaban, tidak akan menjadi pertanyaan stackoverflow yang tepat - itu akan ditutup dengan sengaja.)
ToolmakerSteve
10

Tidak seperti Java, dalam C #: "kelas abstrak harus menyediakan implementasi semua anggota antarmuka yang tercantum dalam daftar kelas dasar kelas. Namun, kelas abstrak diizinkan untuk memetakan metode antarmuka ke metode abstrak."

https://msdn.microsoft.com/en-us/library/Aa664595(v=VS.71).aspx

00jt
sumber
1
Jawaban super jernih dan hebat yang Anda berikan pada kedua situasi, karena terkadang Anda juga mungkin ingin menerapkan perilaku di kelas dasar
VinKel
Salah satu pertanyaan yang muncul di sini adalah: mengapa deklarasi C # boilerplate ini (yang jelas mereka) perlu ada di kelas abstrak, yang kalau tidak bisa ringkas dan lebih pendek (sehingga mengacaukan kelas)? Dalam proyek C # saya, saya punya banyak kelas dan antarmuka abstrak - dan apa yang paling sering saya lakukan adalah menyalin & menempelkan deklarasi metode dalam Visual Studio.
forsberg
5

Mereka tidak harus benar-benar mengimplementasikan antarmuka .
Metode / properti antarmuka bisa abstrak atau bahkan virtual juga. Jadi terserah pada subclass untuk benar-benar mengimplementasikannya.

ntziolis
sumber