Mengapa C # dirancang seperti ini?
Seperti yang saya pahami, antarmuka hanya menggambarkan perilaku, dan melayani tujuan menggambarkan kewajiban kontrak untuk kelas yang mengimplementasikan antarmuka yang perilaku tertentu diimplementasikan.
Jika kelas ingin mengimplementasikan perilaku itu dalam metode bersama, mengapa tidak?
Ini adalah contoh dari apa yang ada dalam pikiran saya:
// These items will be displayed in a list on the screen.
public interface IListItem {
string ScreenName();
...
}
public class Animal: IListItem {
// All animals will be called "Animal".
public static string ScreenName() {
return "Animal";
}
....
}
public class Person: IListItem {
private string name;
// All persons will be called by their individual names.
public string ScreenName() {
return name;
}
....
}
c#
oop
language-features
Kramii
sumber
sumber
IListItem.ScreenName() => ScreenName()
(menggunakan sintaks C # 7) akan mengimplementasikan metode antarmuka secara eksplisit dengan memanggil metode statis. Hal-hal menjadi jelek ketika Anda menambahkan warisan untuk itu, meskipun (Anda harus mengimplementasikan ulang antarmuka)Jawaban:
Dengan asumsi Anda bertanya mengapa Anda tidak bisa melakukan ini:
Ini tidak masuk akal bagi saya, secara semantik. Metode yang ditentukan pada antarmuka harus ada di sana untuk menentukan kontrak untuk berinteraksi dengan objek. Metode statis tidak memungkinkan Anda untuk berinteraksi dengan objek - jika Anda menemukan diri Anda dalam posisi di mana implementasi Anda dapat dibuat statis, Anda mungkin perlu bertanya pada diri sendiri apakah metode itu benar-benar termasuk dalam antarmuka.
Untuk mengimplementasikan contoh Anda, saya akan memberikan Animal properti const, yang masih memungkinkannya diakses dari konteks statis, dan mengembalikan nilai itu dalam implementasi.
Untuk situasi yang lebih rumit, Anda selalu dapat mendeklarasikan metode statis lain dan mendelegasikannya. Dalam mencoba memberikan sebuah contoh, saya tidak dapat memikirkan alasan apa pun Anda akan melakukan sesuatu yang non-sepele dalam konteks statis dan instance, jadi saya akan menghindarkan Anda gumpalan FooBar, dan menganggapnya sebagai indikasi bahwa itu mungkin bukan ide yang bagus.
sumber
public static object MethodName(this IBaseClass base)
dalam kelas statis. Kekurangannya, bagaimanapun, adalah tidak seperti pewarisan antarmuka - ini tidak memaksa / memungkinkan pewaris individu untuk menimpa metodologi dengan baik.Alasan teknis saya (disederhanakan) adalah bahwa metode statis tidak ada dalam vtable , dan situs panggilan dipilih pada waktu kompilasi. Itu alasan yang sama Anda tidak dapat memiliki anggota pengganti atau virtual statis. Untuk lebih jelasnya, Anda memerlukan lulusan CS atau wonk kompiler - yang mana saya tidak memilikinya.
Untuk alasan politik, saya akan mengutip Eric Lippert (yang merupakan kompiler wink, dan memegang gelar Sarjana Matematika, ilmu Komputer dan Matematika Terapan dari University of Waterloo (sumber: LinkedIn ):
Perhatikan bahwa Lippert tidak meninggalkan ruang untuk metode tipe yang disebut:
tetapi belum diyakinkan tentang manfaatnya.
sumber
object
dan bagaimana mereka diizinkan untuk mengimplementasikan antarmuka.Sebagian besar jawaban di sini sepertinya tidak ada artinya. Polimorfisme dapat digunakan tidak hanya antar instance, tetapi juga antar tipe. Ini sering dibutuhkan, ketika kita menggunakan obat generik.
Misalkan kita memiliki tipe parameter dalam metode generik dan kita perlu melakukan beberapa operasi dengannya. Kami tidak ingin melunakkan, karena kami tidak mengetahui konstruktor.
Sebagai contoh:
Sayangnya, saya hanya dapat menemukan alternatif "jelek":
Gunakan refleksi Jelek dan mengalahkan gagasan antarmuka dan polimorfisme.
Buat kelas pabrik yang benar-benar terpisah
Ini mungkin sangat meningkatkan kompleksitas kode. Misalnya, jika kita mencoba memodelkan objek domain, setiap objek akan membutuhkan kelas repositori lain.
Instantiate dan panggil metode antarmuka yang diinginkan
Ini bisa sulit untuk diimplementasikan bahkan jika kita mengendalikan sumber untuk kelas, digunakan sebagai parameter umum. Alasannya adalah, sebagai contoh, kita mungkin membutuhkan instance hanya dalam kondisi "terhubung ke DB" yang terkenal.
Contoh:
untuk menggunakan instantination untuk menyelesaikan masalah antarmuka statis kita perlu melakukan hal-hal berikut:
Ini jelas jelek dan juga tidak perlu mempersulit kode untuk semua metode lain. Jelas, bukan solusi yang elegan!
sumber
public abstract class DBObject<T> where T : DBObject<T>, new()
dan kemudian buat semua kelas DB diwarisi sebagaiDBObject<T>
. Kemudian Anda dapat membuat fungsi mengambil-dengan-kunci fungsi statis dengan tipe kembali T dalam superclass abstrak, membuat fungsi tersebut membuat objek baru T, dan kemudian memanggil dilindungiString GetRetrieveByKeyQuery()
(didefinisikan sebagai abstrak pada superclass) pada objek itu untuk mendapatkan permintaan aktual untuk dieksekusi. Meskipun ini mungkin mendapatkan sedikit topikSaya tahu ini pertanyaan lama, tapi menarik. Contohnya bukan yang terbaik. Saya pikir akan jauh lebih jelas jika Anda menunjukkan kasus penggunaan:
Hanya dengan memiliki metode statis mengimplementasikan sebuah antarmuka tidak akan mencapai apa yang Anda inginkan; apa yang diperlukan adalah memiliki anggota statis sebagai bagian dari antarmuka. Saya pasti bisa membayangkan banyak kasus penggunaan untuk itu, terutama ketika datang untuk dapat membuat sesuatu. Dua pendekatan yang bisa saya tawarkan yang mungkin bisa membantu:
Tidak satu pun dari pendekatan ini yang benar-benar menarik. Di sisi lain, saya akan berharap bahwa jika mekanisme ada di CLR untuk menyediakan fungsionalitas semacam ini dengan bersih, .net akan memungkinkan seseorang untuk menentukan batasan parameter "baru" (karena mengetahui jika kelas memiliki konstruktor dengan tanda tangan tertentu akan tampak menjadi sebanding dalam kesulitan untuk mengetahui apakah ia memiliki metode statis dengan tanda tangan tertentu).
sumber
Saya berpandangan pendek.
Ketika awalnya dirancang, antarmuka hanya dimaksudkan untuk digunakan dengan instance kelas
Itu hanya dengan pengenalan antarmuka sebagai kendala untuk generik tidak menambahkan metode statis ke antarmuka memiliki penggunaan praktis.
(menanggapi komentar :) Saya percaya mengubahnya sekarang akan membutuhkan perubahan pada CLR, yang akan menyebabkan ketidakcocokan dengan majelis yang ada.
sumber
Antarmuka menentukan perilaku suatu objek.
Metode statis tidak menentukan perilaku suatu objek, tetapi perilaku yang mempengaruhi suatu objek dalam beberapa cara.
sumber
Sejauh antarmuka mewakili "kontrak", tampaknya cukup masuk akal bagi kelas statis untuk mengimplementasikan antarmuka.
Argumen di atas semua sepertinya melewatkan poin ini tentang kontrak.
sumber
Karena tujuan dari suatu antarmuka adalah untuk memungkinkan polimorfisme, dapat melewati instance dari sejumlah kelas tertentu yang semuanya telah didefinisikan untuk mengimplementasikan antarmuka yang ditentukan ... menjamin bahwa dalam panggilan polimorfik Anda, kode akan dapat menemukan metode yang Anda panggil. tidak masuk akal untuk memungkinkan metode statis untuk mengimplementasikan antarmuka,
Bagaimana Anda menyebutnya ??
sumber
Whatever<T>() where T:IMyStaticInterface
saya bisa memanggilWhatever<MyClass>()
dan adaT.MyStaticMethod()
di dalamWhatever<T>()
implementasi tanpa perlu contoh. Metode untuk memanggil akan ditentukan dalam runtime. Anda dapat melakukan ini melalui refleksi, tetapi tidak ada "kontrak" yang harus dipaksakan.Mengenai metode statis yang digunakan dalam konteks non-generik, saya setuju bahwa tidak masuk akal untuk memperbolehkannya dalam antarmuka, karena Anda tidak akan dapat memanggil mereka jika Anda memiliki referensi ke antarmuka. Namun ada lubang mendasar dalam desain bahasa yang dibuat dengan menggunakan antarmuka BUKAN dalam konteks polimorfik, tetapi dalam konteks generik. Dalam hal ini antarmuka bukanlah antarmuka sama sekali tetapi merupakan kendala. Karena C # tidak memiliki konsep batasan di luar antarmuka, maka tidak ada fungsi substansial. Inti masalah:
Di sini tidak ada polimorfisme, generik menggunakan tipe objek yang sebenarnya dan memanggil operator + =, tetapi ini gagal karena ia tidak dapat mengatakan dengan pasti bahwa operator itu ada. Solusi sederhana adalah menentukannya dalam batasan; solusi sederhana tidak mungkin karena operator statis dan metode statis tidak dapat berada dalam suatu antarmuka dan (inilah masalahnya) kendala direpresentasikan sebagai antarmuka.
Apa yang dibutuhkan C # adalah tipe kendala nyata, semua antarmuka juga akan menjadi kendala, tetapi tidak semua kendala akan menjadi antarmuka maka Anda bisa melakukan ini:
Sudah banyak pembicaraan tentang membuat IArithmetic untuk semua tipe numerik untuk diimplementasikan, tetapi ada kekhawatiran tentang efisiensi, karena kendala bukan konstruk polimorfik, membuat kendala CArithmetic akan menyelesaikan masalah itu.
sumber
T
harus memiliki statis anggota (mis. pabrik yang memproduksi mesinT
virtual). Bahkan tanpa perubahan runtime, saya pikir akan mungkin untuk menentukan konvensi dan metode pembantu yang akan memungkinkan bahasa untuk menerapkan hal seperti gula sintaksis secara efisien dan interoperable. Jika untuk setiap antarmuka dengan metode statis virtual ada kelas pembantu ...Karena antarmuka berada dalam struktur pewarisan, dan metode statis tidak mewarisi dengan baik.
sumber
Apa yang tampaknya Anda inginkan akan memungkinkan metode statis dipanggil melalui Tipe atau instance dari tipe itu. Paling tidak ini akan menghasilkan ambiguitas yang bukan sifat yang diinginkan.
Akan ada perdebatan tanpa akhir tentang apakah itu penting, yang merupakan praktik terbaik dan apakah ada masalah kinerja yang melakukannya dengan satu atau lain cara. Dengan tidak mendukungnya, C # menyelamatkan kita karena harus mengkhawatirkannya.
Kemungkinan juga bahwa penyusun yang sesuai dengan keinginan ini akan kehilangan beberapa optimisasi yang mungkin datang dengan pemisahan yang lebih ketat antara metode instance dan metode statis.
sumber
Anda dapat menganggap metode statis dan metode non-statis suatu kelas sebagai antarmuka yang berbeda. Ketika dipanggil, metode statis menyelesaikan ke objek kelas statis tunggal, dan metode non-statis menyelesaikan contoh kelas yang Anda hadapi. Jadi, jika Anda menggunakan metode statis dan non-statis dalam sebuah antarmuka, Anda akan secara efektif mendeklarasikan dua antarmuka ketika kita ingin antarmuka digunakan untuk mengakses satu hal yang kohesif.
sumber
Untuk memberikan contoh di mana saya kehilangan implementasi statis dari metode antarmuka atau apa yang diperkenalkan Mark Brackett sebagai "apa yang disebut metode metode":
Saat membaca dari penyimpanan database, kami memiliki kelas DataTable generik yang menangani pembacaan dari tabel struktur apa pun. Semua informasi spesifik tabel dimasukkan ke dalam satu kelas per tabel yang juga menyimpan data untuk satu baris dari DB dan yang harus mengimplementasikan antarmuka IDataRow. Termasuk dalam IDataRow adalah deskripsi struktur tabel untuk dibaca dari database. DataTable harus meminta datastructure dari IDataRow sebelum membaca dari DB. Saat ini terlihat seperti:
GetDataStructure hanya diperlukan satu kali untuk setiap tabel untuk dibaca, overhead untuk instantiating satu lagi contoh minimal. Namun, akan lebih baik dalam hal ini di sini.
sumber
FYI: Anda bisa mendapatkan perilaku serupa dengan apa yang Anda inginkan dengan membuat metode ekstensi untuk antarmuka. Metode ekstensi akan menjadi perilaku statis yang dibagi dan tidak dapat ditimpa. Namun, sayangnya, metode statis ini tidak akan menjadi bagian dari kontrak.
sumber
Antarmuka adalah set abstrak dari fungsionalitas yang tersedia yang tersedia.
Apakah atau tidak metode di antarmuka itu bertindak sebagai statis atau tidak adalah detail implementasi yang harus disembunyikan di balik antarmuka . Akan salah untuk mendefinisikan metode antarmuka sebagai statis karena Anda tidak perlu memaksakan metode yang akan diterapkan dengan cara tertentu.
Jika metode didefinisikan sebagai statis, kelas yang mengimplementasikan antarmuka tidak akan dienkapsulasi sebagaimana mestinya. Enkapsulasi adalah hal yang baik untuk diperjuangkan dalam desain berorientasi objek (saya tidak akan membahas mengapa, Anda dapat membacanya di sini: http://en.wikipedia.org/wiki/Object-oriented ). Karena alasan ini, metode statis tidak diizinkan di antarmuka.
sumber
Kelas statis harus dapat melakukan ini sehingga dapat digunakan secara umum. Saya malah harus menerapkan Singleton untuk mencapai hasil yang diinginkan.
Saya memiliki banyak kelas Lapisan Bisnis Statis yang menerapkan metode CRUD seperti "Buat", "Baca", "Perbarui", "Hapus" untuk setiap jenis entitas seperti "Pengguna", "Tim", dll .. Lalu saya membuat basis kontrol yang memiliki properti abstrak untuk kelas Business Layer yang menerapkan metode CRUD. Ini memungkinkan saya untuk mengotomatiskan operasi "Buat", "Baca", "Perbarui", "Hapus" dari kelas dasar. Saya harus menggunakan Singleton karena keterbatasan statis.
sumber
Kebanyakan orang sepertinya lupa bahwa dalam OOP Classes adalah objek juga, dan karena itu mereka memiliki pesan, yang karena alasan tertentu c # memanggil "metode statis". Fakta bahwa ada perbedaan antara objek instan dan objek kelas hanya menunjukkan kekurangan atau kekurangan dalam bahasa. Optimis tentang c # ...
sumber
OK di sini adalah contoh membutuhkan 'metode tipe'. Saya membuat salah satu dari sekumpulan kelas berdasarkan beberapa sumber XML. Jadi saya punya
fungsi yang disebut pada gilirannya di setiap kelas.
Fungsi ini harus statis karena kalau tidak, kita membuang-buang waktu membuat objek yang tidak pantas. Seperti yang ditunjukkan @Ian Boyde, ini bisa dilakukan di kelas pabrik, tetapi ini hanya menambah kompleksitas.
Akan lebih baik menambahkannya ke antarmuka untuk memaksa implementor kelas mengimplementasikannya. Ini tidak akan menyebabkan overhead yang signifikan - ini hanya pemeriksaan waktu kompilasi / tautan dan tidak mempengaruhi vtable.
Namun, itu juga akan menjadi peningkatan yang cukup kecil. Karena metode ini statis, saya sebagai penelepon, harus memanggilnya secara eksplisit sehingga mendapatkan kompilasi kesalahan segera jika tidak diterapkan. Mengizinkan untuk ditentukan pada antarmuka akan berarti kesalahan ini muncul sedikit lebih awal dalam siklus pengembangan, tetapi ini sepele dibandingkan dengan masalah antarmuka rusak lainnya.
Jadi ini adalah fitur potensial kecil yang mungkin sebaiknya tidak diseimbangkan.
sumber
Fakta bahwa kelas statis diimplementasikan dalam C # oleh Microsoft menciptakan contoh khusus dari kelas dengan elemen statis hanyalah keanehan bagaimana fungsionalitas statis dicapai. Ini bukan poin teoretis.
Antarmuka HARUS menjadi deskriptor antarmuka kelas - atau bagaimana berinteraksi dengan, dan itu harus mencakup interaksi yang statis. Definisi umum antarmuka (dari Meriam-Webster): tempat atau area tempat berbagai hal saling bertemu dan berkomunikasi atau saling memengaruhi. Ketika Anda menghilangkan komponen statis dari kelas atau kelas statis sama sekali, kami mengabaikan sebagian besar bagaimana anak-anak nakal ini berinteraksi.
Berikut ini adalah contoh yang sangat jelas tentang di mana bisa menggunakan antarmuka dengan kelas statis akan sangat berguna:
Saat ini, saya menulis kelas statis yang berisi metode ini tanpa memeriksa untuk memastikan bahwa saya belum melupakan apa pun. Seperti masa lalu pemrograman yang buruk sebelum OOP.
sumber
C # dan CLR harus mendukung metode statis di antarmuka seperti halnya Java. Pengubah statis adalah bagian dari definisi kontrak dan memang memiliki makna, khususnya bahwa perilaku dan nilai kembali tidak bervariasi berdasarkan pada contoh meskipun mungkin masih berbeda dari panggilan ke panggilan.
Yang mengatakan, saya merekomendasikan bahwa ketika Anda ingin menggunakan metode statis dalam suatu antarmuka dan tidak bisa, gunakan anotasi sebagai gantinya. Anda akan mendapatkan fungsionalitas yang Anda cari.
sumber
Saya pikir jawaban singkatnya adalah "karena tidak ada gunanya". Untuk memanggil metode antarmuka, Anda memerlukan turunan tipe. Dari metode instan Anda dapat memanggil metode statis apa pun yang Anda inginkan.
sumber
Saya pikir pertanyaannya adalah pada kenyataan bahwa C # membutuhkan kata kunci lain, untuk situasi seperti ini. Anda menginginkan metode yang nilai pengembaliannya hanya bergantung pada jenis yang dipanggil. Anda tidak dapat menyebutnya "statis" jika jenis kata tidak dikenal. Tetapi begitu jenisnya diketahui, itu akan menjadi statis. "Statis yang belum terselesaikan" adalah idenya - ini belum statis, tetapi begitu kita mengetahui tipe penerima, itu akan menjadi. Ini adalah konsep yang sangat baik, itulah sebabnya programmer terus memintanya. Tapi itu tidak cukup cocok dengan cara para perancang berpikir tentang bahasa.
Karena tidak tersedia, saya menggunakan metode non-statis dengan cara yang ditunjukkan di bawah ini. Tidak terlalu ideal, tetapi saya tidak bisa melihat pendekatan yang lebih masuk akal, setidaknya tidak untuk saya.
sumber
Jadi jika Anda ingin mengakses metode Kontrak Antarmuka Anda harus membuat objek. Itu selalu harus yang tidak diperbolehkan dalam hal metode statis. Kelas statis, metode, dan variabel tidak pernah memerlukan objek dan memuat dalam memori tanpa membuat objek dari area tersebut (atau kelas) atau Anda dapat mengatakan tidak memerlukan Pembuatan Objek.
sumber
Secara konseptual tidak ada alasan mengapa antarmuka tidak dapat mendefinisikan kontrak yang mencakup metode statis.
Untuk implementasi bahasa C # saat ini, pembatasan ini disebabkan oleh tunjangan warisan kelas dasar dan antarmuka. Jika "class SomeBaseClass" mengimplementasikan "interface ISomeInterface" dan "class SomeDerivedClass: SomeBaseClass, ISomeInterface" juga mengimplementasikan antarmuka, metode statis untuk mengimplementasikan metode antarmuka akan gagal dikompilasi karena metode statis tidak dapat memiliki tanda tangan yang sama dengan metode instance (yang akan hadir di kelas dasar untuk mengimplementasikan antarmuka).
Kelas statis secara fungsional identik dengan singleton dan melayani tujuan yang sama dengan singleton dengan sintaks yang lebih bersih. Karena singleton dapat mengimplementasikan antarmuka, implementasi antarmuka oleh statika secara konseptual valid.
Jadi itu hanya bermuara pada batasan konflik nama C # misalnya dan metode statis dari nama yang sama di seluruh warisan. Tidak ada alasan mengapa C # tidak dapat "ditingkatkan" untuk mendukung kontrak metode statis (antarmuka).
sumber
Ketika sebuah kelas mengimplementasikan antarmuka, itu menciptakan instance untuk anggota antarmuka. Sementara tipe statis tidak memiliki instance, tidak ada gunanya memiliki tanda tangan statis di antarmuka.
sumber