Saya tahu bahwa Java mengimplementasikan parametric polymorphism (Generics) dengan penghapusan. Saya mengerti apa itu penghapusan.
Saya tahu bahwa C # mengimplementasikan polimorfisme parametrik dengan reifikasi. Saya tahu itu bisa membuat Anda menulis
public void dosomething(List<String> input) {}
public void dosomething(List<Int> input) {}
atau bahwa Anda bisa tahu pada saat runtime apa jenis parameter dari beberapa jenis parameterised adalah, tapi saya tidak mengerti apa yang .
- Apa yang dimaksud dengan tipe reified?
- Apa yang dimaksud dengan nilai reified?
- Apa yang terjadi ketika suatu jenis / nilai diverifikasi?
c#
generics
reification
Martijn
sumber
sumber
if
reication adalah proses mengubahswitch
konstruk kembali keif
/else
, ketika sebelumnya telah dikonversi dariif
/else
keswitch
...Jawaban:
Reifikasi adalah proses mengambil sesuatu yang abstrak dan menciptakan sesuatu yang konkret.
Istilah reifikasi dalam C # generics mengacu pada proses dimana definisi tipe generik dan satu atau lebih argumen tipe generik (hal abstrak) digabungkan untuk membuat tipe generik baru (hal konkret).
Untuk mengatakannya secara berbeda, itu adalah proses mengambil definisi
List<T>
danint
dan menghasilkanList<int>
jenis yang konkret .Untuk memahaminya lebih lanjut, bandingkan pendekatan berikut:
Dalam Java generics, definisi tipe generik diubah menjadi dasarnya satu tipe generik konkret yang dibagikan di semua kombinasi argumen tipe yang diizinkan. Dengan demikian, beberapa tipe (level kode sumber) dipetakan ke satu tipe (level biner) - tetapi sebagai hasilnya, informasi tentang argumen tipe instance dihilangkan dalam instance tersebut (tipe erasure) .
Dalam C # generics, definisi tipe generik dipertahankan dalam memori saat runtime. Setiap kali tipe beton baru diperlukan, lingkungan runtime menggabungkan definisi tipe generik dan argumen tipe dan membuat tipe baru (reifikasi). Jadi kita mendapatkan tipe baru untuk setiap kombinasi argumen tipe, saat runtime .
System.Type
kelas (bahkan jika kombinasi argumen tipe generik tertentu yang Anda instantiating tidak t muncul dalam kode sumber Anda secara langsung).Dalam template C ++, definisi template dipertahankan dalam memori pada waktu kompilasi. Setiap kali instantiasi baru dari tipe templat diperlukan dalam kode sumber, kompiler menggabungkan definisi templat dan argumen templat dan membuat tipe baru. Jadi kami mendapatkan tipe unik untuk setiap kombinasi argumen template, pada waktu kompilasi .
sumber
Reifikasi berarti secara umum (di luar ilmu komputer) "untuk membuat sesuatu yang nyata".
Dalam pemrograman, sesuatu dibenarkan jika kita dapat mengakses informasi dalam bahasa itu sendiri.
Untuk dua contoh yang sepenuhnya tidak berhubungan dengan generik tentang sesuatu yang C # lakukan dan tidak miliki terverifikasi, mari kita ambil metode dan akses memori.
Bahasa OO umumnya memiliki metode , (dan banyak yang tidak memiliki fungsi yang serupa meskipun tidak terikat ke kelas). Karena itu, Anda dapat menentukan metode dalam bahasa tersebut, menyebutnya, mungkin menimpanya, dan sebagainya. Tidak semua bahasa tersebut memungkinkan Anda menangani metode itu sendiri sebagai data untuk suatu program. C # (dan benar-benar, .NET, bukan C #) memungkinkan Anda menggunakan
MethodInfo
objek yang mewakili metode, jadi dalam metode C # diverifikasi. Metode dalam C # adalah "objek kelas satu".Semua bahasa praktis memiliki beberapa cara untuk mengakses memori komputer. Dalam bahasa tingkat rendah seperti C, kita bisa berurusan langsung dengan pemetaan antara alamat numerik yang digunakan oleh komputer, jadi suka
int* ptr = (int*) 0xA000000; *ptr = 42;
itu masuk akal (selama kita punya alasan yang bagus untuk mencurigai bahwa mengakses alamat memori0xA000000
dengan cara ini tidak akan menang ' t meledakkan sesuatu). Dalam C # ini tidak masuk akal (kita bisa memaksakannya dalam. NET, tetapi dengan manajemen memori .NET memindahkan hal-hal di sekitar itu tidak mungkin berguna). C # tidak memiliki alamat memori terverifikasi.Jadi, sebagaimana ditolak berarti "menjadi nyata", "jenis yang ditegaskan" adalah jenis yang dapat kita "bicarakan" dalam bahasa yang dimaksud.
Dalam generik ini berarti dua hal.
Salah satunya adalah bahwa
List<string>
adalah jenis sepertistring
atauint
yang. Kita dapat membandingkan jenis itu, mendapatkan namanya, dan menanyakannya:Konsekuensi dari hal ini adalah bahwa kita dapat "berbicara tentang" tipe parameter metode generik (atau metode kelas generik) dalam metode itu sendiri:
Sebagai aturan, melakukan ini terlalu "bau", tetapi memiliki banyak kasus yang bermanfaat. Sebagai contoh, lihat:
Ini tidak melakukan banyak perbandingan antara jenis
TSource
dan berbagai jenis untuk perilaku yang berbeda (umumnya merupakan tanda bahwa Anda seharusnya tidak menggunakan obat generik sama sekali), tetapi memang memecah antara jalur kode untuk jenis yang dapatnull
(harus kembalinull
jika tidak ada elemen yang ditemukan, dan tidak boleh membuat perbandingan untuk menemukan minimum jika salah satu elemen dibandingkan adalahnull
) dan jalur kode untuk tipe yang tidak dapatnull
(harus dibuang jika tidak ada elemen yang ditemukan, dan tidak perlu khawatir tentang kemungkinannull
elemen ).Karena
TSource
"nyata" dalam metode ini, perbandingan ini dapat dibuat baik pada saat runtime atau waktu jitting (umumnya waktu jitting, tentu saja kasus di atas akan melakukannya pada waktu jitting dan tidak menghasilkan kode mesin untuk jalur yang tidak diambil) dan kami memiliki pisahkan versi "nyata" dari metode untuk setiap kasus. (Meskipun sebagai optimasi, kode mesin dibagikan untuk metode yang berbeda untuk parameter tipe tipe referensi yang berbeda, karena dapat tanpa mempengaruhi ini, dan karenanya kita dapat mengurangi jumlah kode mesin yang dipasangkan).(Tidak umum untuk berbicara tentang reifikasi tipe generik dalam C # kecuali jika Anda juga berurusan dengan Java, karena dalam C # kami hanya menerima reifikasi ini; semua tipe diverifikasi. Di Jawa, tipe non-generik disebut sebagai reified karena itu adalah perbedaan antara mereka dan tipe generik).
sumber
Min
berguna di atas? Sangat sulit untuk memenuhi perilakunya yang terdokumentasi.Enumerable.Min<TSource>
berbeda karena tidak melempar untuk tipe non-referensi pada koleksi kosong, tetapi mengembalikan default (TSource), dan hanya didokumentasikan sebagai "Mengembalikan nilai minimum dalam urutan umum." Saya berpendapat keduanya harus membuang koleksi kosong, atau bahwa elemen "nol" harus dilewatkan sebagai baseline, dan pembanding / fungsi perbandingan harus selalu diteruskan)Seperti yang sudah dicatat oleh duffymo, "reifikasi" bukanlah perbedaan utama.
Di Jawa, obat generik pada dasarnya ada untuk meningkatkan dukungan waktu kompilasi - ini memungkinkan Anda untuk menggunakan koleksi mis. Yang diketik dalam kode Anda, dan mengatur keselamatan jenis untuk Anda. Namun, ini hanya ada pada waktu kompilasi - kode kode yang dikompilasi tidak lagi memiliki pengertian generik; semua tipe generik ditransformasikan menjadi tipe "konkret" (menggunakan
object
jika tipe generik tidak terikat), menambahkan konversi tipe dan memeriksa jenis sesuai kebutuhan.Dalam .NET, obat generik adalah fitur integral dari CLR. Saat Anda mengompilasi tipe generik, itu tetap generik di IL yang dihasilkan. Bukan hanya ditransformasikan menjadi kode non-generik seperti di Jawa.
Ini memiliki beberapa dampak pada bagaimana obat generik bekerja dalam praktiknya. Sebagai contoh:
SomeType<?>
mengizinkan Anda untuk melewati implementasi konkret dari tipe generik yang diberikan. C # tidak dapat melakukan ini - setiap tipe generik spesifik ( reified ) adalah tipenya sendiri.object
. Ini dapat memiliki dampak kinerja ketika menggunakan tipe nilai dalam obat generik tersebut. Di C #, ketika Anda menggunakan tipe nilai dalam tipe generik, itu tetap tipe nilai.Untuk memberikan sampel, anggap Anda memiliki
List
tipe generik dengan satu argumen generik. Di Jawa,List<String>
danList<Int>
pada akhirnya akan menjadi tipe yang sama persis saat runtime - tipe generik hanya benar-benar ada untuk kode waktu kompilasi. Semua panggilan ke misGetValue
akan ditransformasikan ke(String)GetValue
dan(Int)GetValue
masing - masing.Dalam C #,
List<string>
danList<int>
ada dua jenis yang berbeda. Mereka tidak dapat dipertukarkan, dan keamanan jenisnya juga diberlakukan pada saat runtime. Tidak peduli apa yang Anda lakukan,new List<int>().Add("SomeString")
akan tidak pernah bekerja - penyimpanan yang mendasari dalamList<int>
adalah benar-benar beberapa array integer, sedangkan di Jawa, maka perlu sebuahobject
array yang. Di C #, tidak ada pemain yang terlibat, tidak ada tinju dll.Ini juga harus menjelaskan mengapa C # tidak dapat melakukan hal yang sama dengan Java
SomeType<?>
. Di Jawa, semua tipe generik "berasal dari"SomeType<?>
akhirnya menjadi tipe yang sama persis. Dalam C #, semua berbagai spesifikSomeType<T>
adalah tipe mereka sendiri. Menghapus pemeriksaan waktu kompilasi, dimungkinkan untuk lulusSomeType<Int>
alih-alihSomeType<String>
(dan sebenarnya, semua ituSomeType<?>
artinya "abaikan pemeriksaan waktu kompilasi untuk jenis generik yang diberikan"). Dalam C #, itu tidak mungkin, bahkan untuk tipe turunan (yaitu, Anda tidak dapat melakukannyaList<object> list = (List<object>)new List<string>();
meskipunstring
berasal dariobject
).Kedua implementasi memiliki pro dan kontra. Sudah ada beberapa kali ketika saya ingin bisa membiarkan hanya
SomeType<?>
sebagai argumen dalam C # - tetapi itu tidak masuk akal cara kerja C # generics.sumber
List<>
,Dictionary<,>
dan seterusnya dalam C #, tetapi kesenjangan antara itu dan daftar konkret atau kamus tertentu membutuhkan sedikit refleksi untuk menjembatani. Perbedaan pada antarmuka memang membantu dalam beberapa kasus di mana kita mungkin pernah ingin menjembatani kesenjangan itu dengan mudah, tetapi tidak semua.List<>
instantiate tipe generik spesifik baru - tetapi masih berarti membuat tipe spesifik yang Anda inginkan. Tetapi Anda tidak dapat menggunakanList<>
sebagai argumen, misalnya. Tapi ya, setidaknya ini memungkinkan Anda untuk menjembatani kesenjangan menggunakan refleksi.T
dapat memenuhi batasan tipe lokasi penyimpananU
adalah ketikaT
danU
merupakan tipe yang sama, atauU
merupakan tipe yang dapat menyimpan referensi ke instanceT
. Tidak mungkin memiliki lokasi penyimpanan tipe yang bermaknaSomeType<?>
tetapi secara teori dimungkinkan untuk memiliki batasan generik dari tipe tersebut.Reifikasi adalah konsep pemodelan berorientasi objek.
Reify adalah kata kerja yang berarti "membuat sesuatu abstrak nyata" .
Ketika Anda melakukan pemrograman berorientasi objek, biasanya memodelkan objek dunia nyata sebagai komponen perangkat lunak (misalnya Window, Button, Person, Bank, Vehicle, dll.)
Juga umum untuk merevisi konsep abstrak menjadi komponen juga (misalnya WindowListener, Broker, dll.)
sumber