Mengapa .NET framework tidak memiliki konsep kelas sebagai tipe kelas satu?

20

Sudah terkenal bagi mereka yang akrab dengan sejarah bahwa C # dan .NET framework dimulai sebagai dasarnya "Delphi ditulis ulang untuk merasa seperti Java," dirancang oleh kepala pengembang di belakang Delphi, Anders Hejlsberg. Hal-hal telah menyimpang sedikit sejak itu, tetapi sejak awal kemiripannya begitu jelas sehingga bahkan ada beberapa spekulasi serius bahwa .NET sebenarnya awalnya produk Borland.

Tapi saya telah melihat beberapa .NET belakangan ini, dan salah satu fitur yang paling menarik dan berguna dari Delphi tampaknya hilang seluruhnya: konsep kelas sebagai tipe data kelas satu. Bagi mereka yang tidak terbiasa dengan itu, tipe TClassmewakili referensi ke kelas, mirip dengan Typetipe .NET. Tapi di mana. NET menggunakan Typeuntuk refleksi, Delphi menggunakan TClasssebagai bagian built-in yang sangat penting dari bahasa. Hal ini memungkinkan untuk berbagai idiom berguna yang tidak dan tidak bisa ada tanpa itu, seperti variabel subtipe kelas dan metode kelas virtual.

Setiap bahasa OO memiliki metode virtual, di mana kelas yang berbeda menerapkan konsep dasar yang sama dari metode dengan cara yang berbeda, dan kemudian metode yang tepat dipanggil pada saat runtime berdasarkan pada jenis objek objek yang dipanggil. Delphi memperluas konsep ini ke kelas: jika Anda memiliki referensi TClass yang didefinisikan sebagai subtipe kelas tertentu ( class of TMyClassartinya variabel dapat menerima referensi kelas apa pun yang diwarisi dari TMyClass, tetapi bukan apa pun di luar heirarki) yang memiliki metode virtual ruang lingkup yang melekat pada itu, mereka dapat dipanggil tanpa instance dengan menggunakan tipe kelas yang sebenarnya. Menerapkan pola ini ke konstruktor membuat implementasi pabrik menjadi sepele, misalnya.

Tampaknya tidak ada yang setara di .NET. Dengan referensi kelas yang berguna (dan terutama konstruktor virtual dan metode kelas virtual lainnya!), Adakah yang mengatakan sesuatu tentang mengapa mereka ditinggalkan?

Contoh spesifik

Bentuk Deserialisasi

Delphi VCL menyimpan formulir dalam DFMformat, DSL untuk menggambarkan hierarki komponen. Saat pembaca formulir mem-parsing data DFM, itu berjalan melintasi objek yang digambarkan seperti ini:

object Name: ClassName
   property = value
   property = value
   ...
   object SubObjectName: ClassName
      ...
   end
end

Yang menarik di sini adalah ClassNamebagiannya. Setiap kelas komponen mendaftarkannya TClassdengan sistem streaming komponen pada initializationwaktu itu (bayangkan konstruktor statis, hanya sedikit berbeda, dijamin akan terjadi segera pada saat startup.) Ini mendaftarkan setiap kelas dalam sebuah hashmap-class TClass dengan nama kelas sebagai kunci.

Setiap komponen berasal dari TComponent, yang memiliki konstruktor virtual yang mengambil argumen tunggal Owner: TComponent,. Setiap komponen dapat menimpa konstruktor ini untuk menyediakan inisialisasi sendiri. Ketika pembaca DFM membaca nama kelas, itu mencari nama dalam hashmap yang disebutkan di atas dan mengambil referensi kelas yang sesuai (atau menimbulkan pengecualian jika tidak ada di sana), kemudian memanggil konstruktor TComponent virtual di atasnya, yang dikenal baik karena fungsi pendaftaran mengambil referensi kelas yang diperlukan untuk turun dari TComponent, dan Anda berakhir dengan objek dengan tipe yang tepat.

Kurangnya ini, setara WinForms adalah ... well ... berantakan besar untuk terus terang, membutuhkan bahasa .NET baru untuk sepenuhnya menerapkan kembali bentuk sendiri (de) serialisasi. Ini agak mengejutkan ketika Anda memikirkannya; karena inti dari memiliki CLR adalah membiarkan banyak bahasa menggunakan infrastruktur dasar yang sama, sistem gaya DFM akan sangat masuk akal.

Kemungkinan diperpanjang

Kelas manajer gambar yang saya tulis dapat diberikan dengan sumber data (seperti jalur ke file gambar Anda) dan kemudian memuat objek gambar baru secara otomatis jika Anda mencoba untuk mengambil nama yang tidak ada dalam koleksi tetapi tersedia di sumber data. Ini memiliki variabel kelas yang diketik sebagai class ofkelas gambar dasar, mewakili kelas dari setiap objek baru yang akan dibuat. Muncul dengan default, tetapi ada beberapa poin, ketika membuat gambar baru dengan tujuan khusus, bahwa gambar harus diatur dengan cara yang berbeda. (Membuatnya tanpa saluran alfa, mengambil metadata khusus dari file PNG untuk menentukan ukuran sprite, dll.)

Ini dapat dilakukan dengan menulis sejumlah besar kode konfigurasi dan mengirimkan opsi khusus ke semua metode yang mungkin berakhir dengan membuat objek baru ... atau Anda bisa membuat subkelas dari kelas gambar dasar yang menimpa metode virtual di mana aspek yang dimaksud akan dikonfigurasikan, dan kemudian menggunakan blok coba / akhirnya untuk sementara mengganti properti "kelas default" yang diperlukan dan kemudian mengembalikannya. Melakukannya dengan variabel referensi kelas jauh lebih sederhana, dan bukan sesuatu yang bisa dilakukan dengan obat generik.

Mason Wheeler
sumber
3
Bisakah Anda memberikan satu atau dua contoh konkret di mana a TClassberguna, dengan beberapa kode sampel? Dalam penelitian internet sepintas saya tentang TClass, saya menemukan yang TClassdapat diedarkan sebagai parameter. Ini dilakukan di .NET menggunakan Generics. Metode pabrik ditandai dengan sederhana staticdi .NET, dan tidak memerlukan instance kelas untuk mengeksekusi.
Robert Harvey
7
@RobertHarvey: Bagi saya, secara pribadi, C # mulai lebih masuk akal begitu saya berhenti melihatnya sebagai Java / C ++ yang dimuat ulang dan mulai memperlakukannya sebagai Modula-2 dengan objek. Itu sama dengan Java: semua orang mengatakan itu dipengaruhi oleh C ++, tapi itu tidak benar. Pengaruh utamanya adalah Objective-C (dan Smalltalk melalui itu), dan Jawa akan membuat banyak lebih masuk akal sekali Anda memperlakukannya sebagai Smalltalk dengan jenis bukan C ++ dengan GC.
Jörg W Mittag
3
@RobertHarvey: TClassadalah fitur bahasa dasar yang membutuhkan dukungan kompiler. Anda tidak dapat "menulis sendiri" tanpa menulis bahasa Anda sendiri, dan untuk .NET bahkan itu tidak akan cukup karena model objek didefinisikan oleh CLR, bukan oleh bahasa individual. Ini adalah sesuatu yang benar-benar harus menjadi bagian dari .NET framework itu sendiri, atau tidak bisa ada.
Mason Wheeler
4
Pertama-tama, saya dapat mengatakan dengan sangat yakin bahwa .NET bukanlah produk "Borland" pada awalnya. Bagaimana saya tahu ini? Saya (masih) bagian dari tim inti asli yang mengembangkan Delphi. Saya bekerja erat dengan Anders, Chuck, Gary dan yang lainnya. Tentu saja, saya yakin Anda tahu ini. Adapun keberadaan referensi kelas (seperti TClass dan konstruksi serupa disebut) di. NET kemungkinan dianggap tidak perlu karena adanya informasi jenis run-time yang kaya diakses. Delphi memiliki tipe informasi yang jauh lebih sedikit pada awalnya dan referensi kelas adalah kompromi.
Allen Bauer

Jawaban:

5

.NET (CLR) adalah generasi ketiga dari Microsoft Component Object Model (COM), yang pada awalnya disebut sebagai "COM + runtime". Microsoft Visual Basic dan pasar kontrol COM / ActiveX memiliki pengaruh lebih besar pada pilihan kompatibilitas arsitektur CLR daripada Borland Delphi. (Harus diakui fakta bahwa Delphi telah mengadopsi kontrol ActiveX tentu saja membantu menumbuhkan ekosistem ActiveX, tetapi COM / ActiveX ada sebelum Delphi)

Arsitektur COM dikerjakan dalam C (bukan C ++) dan berfokus pada antarmuka, bukan kelas. Lebih jauh lagi, didukung komposisi objek, yang berarti bahwa objek COM sebenarnya dapat terdiri dari beberapa objek yang berbeda, dengan antarmuka IUnknown yang menghubungkan keduanya. Tapi IUnknown tidak memiliki peran dalam pembuatan objek COM, yang dirancang untuk menjadi bahasa-independen mungkin. Pembuatan objek umumnya ditangani oleh IClassFactory, dan refleksi oleh ITypeLibrary dan antarmuka terkait. Pemisahan masalah ini tidak tergantung pada bahasa implementasi, dan fitur-fitur dari masing-masing antarmuka COM dijaga agar tetap minimal dan ortogonal.

Jadi sebagai akibat dari popularitas kontrol COM dan ActiveX, arsitektur .NET dibangun untuk mendukung COM IUnknown, IClassFactory, dan ITypeLibrary. Dalam COM, antarmuka ini tidak harus pada objek yang sama, jadi penggabungan ini tidak selalu masuk akal.

Burt_Harris
sumber