Чому рамка .NET не має поняття класів як першокласних типів?


20

Тим, хто знайомий з історією, добре відомо, що C # та .NET Framework почали створюватись як «Delphi переписаний, щоб відчути себе Java», архітектор головного розробника Delphi Андерса Хейлсберга. З тих пір речі значно розійшлися, але на початку подібність була настільки очевидною, що навіть існували серйозні міркування про те, що .NET насправді був продуктом Borland.

Але останнім часом я розглядав деякі речі .NET, і, здається, одна з найцікавіших і корисних функцій від Delphi повністю відсутня: концепція класів як першокласного типу даних. Для тих, хто з ним не знайомий, тип TClassпредставляє посилання на клас, подібний до Typeтипу в .NET. Але там, де .NET використовує Typeдля роздумів, Delphi використовує TClassяк дуже важливу вбудовану частину мови. Він дозволяє використовувати різні корисні ідіоми, які просто не існують і не можуть існувати без нього, такі як змінні підтипи класів та методи віртуального класу.

У кожній мові ОО є віртуальні методи, в яких різні класи по-різному реалізують одне і те ж фундаментальне поняття методу, і тоді правильний метод викликається під час виконання на основі фактичного типу екземпляра об'єкта, на який він викликається. Delphi поширює це поняття на класи: якщо у вас є посилання TClass, визначений як специфічний підтип класу (тобто class of TMyClassозначає, що змінна може приймати будь-яку посилання класу, що успадковується від TMyClass, але не що-небудь поза герархією), до якого додаються віртуальні методи класового діапазону це, їх можна викликати без екземпляра, використовуючи фактичний тип класу. Застосування цього шаблону до конструкторів, наприклад, робить тривиальну реалізацію заводу.

Здається, немає нічого еквівалентного в .NET. З настільки ж корисними, як і посилання на клас (і особливо віртуальні конструктори та інші методи віртуального класу!), Хтось сказав що-небудь про те, чому їх залишили?

Конкретні приклади

Десеріалізація форми

Delphi VCL зберігає форми у DFMформаті, DSL для опису ієрархії компонентів. Коли зчитувач форми аналізує дані DFM, він проходить через об'єкти, описані так:

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

Цікавим тут є ClassNameчастина. Кожен клас компонентів реєструє його TClassразом із системою потокової передачі компонентів initialization(мислити статичні конструктори, лише дещо інші, гарантовано відбудуться негайно під час запуску.) Цей регістр реєструє кожен клас у рядку-> хешмак TClass з ім'ям класу як ключовим.

Кожен компонент відбувається з TComponent, який має віртуальний конструктор , який приймає один аргумент, Owner: TComponent. Будь-який компонент може замінити цей конструктор, щоб забезпечити його власну ініціалізацію. Коли зчитувач DFM читає ім'я класу, він шукає ім'я у вищезгаданій хешмапі та отримує відповідну посилання класу (або збільшує виняток, якщо його немає), а потім викликає віртуальний конструктор TComponent на ньому, який, як відомо, є хорошим тому що функція реєстрації містить посилання на клас, необхідний для спуску з TComponent, і ви отримуєте об'єкт відповідного типу.

Не маючи цього, еквівалент WinForms - це ... ну ... великий безлад, щоб сказати це прямо, вимагаючи будь-якої нової мови .NET, щоб повністю реалізувати власну форму (де) серіалізацію. Це трохи шокує, коли ти думаєш про це; Оскільки суть CLR полягає в тому, щоб дозволити декілька мов використовувати одну і ту ж основну інфраструктуру, система DFM мала б ідеальний сенс.

Розширюваність

Клас менеджера зображень, про який я писав, може надавати джерело даних (наприклад, шлях до файлів зображень), а потім автоматично завантажувати нові об’єкти зображень, якщо ви намагаєтеся отримати ім’я, яке не знаходиться в колекції, але воно доступне у джерелі даних. Він має змінну класу, введену як class ofбазовий клас зображення, що представляє клас будь-яких нових об'єктів, які слід створити. Він поставляється за замовчуванням, але є деякі моменти, коли створюються нові зображення із спеціальними цілями, що зображення слід налаштовувати різними способами. (Створення його без альфа-каналу, отримання спеціальних метаданих з файлу PNG для визначення розміру спрайту тощо)

Це можна зробити, записавши велику кількість конфігураційного коду та передавши спеціальні параметри всім методам, які могли б у результаті створити новий об'єкт ... або ви могли просто створити підклас базового класу зображень, який перекриває віртуальний метод, де відповідний аспект конфігурується, а потім використовуйте блок "спробувати / остаточно", щоб тимчасово замінити властивість "класу за замовчуванням" за необхідності та відновити його. Зробити це за допомогою змінних посилань класу набагато простіше, і це не те, що можна зробити замість генеричних даних.



3
Чи можете ви надати один чи два конкретні приклади, де а TClassкорисний, з деяким зразком коду? У ході мого короткого дослідження в Інтернеті TClassя виявляю, що TClassйого можна передати як параметр. Це робиться в .NET за допомогою Generics. Фабричні методи просто позначені staticу .NET, і для цього не потрібен екземпляр класу.
Роберт Харві

7
@RobertHarvey: Особисто для мене C # почав мати набагато більше сенсу, як тільки я перестав дивитись на нього, як Java / C ++ перезавантажувався і почав трактувати його як Modula-2 з об'єктами. Так само і з Java: всі кажуть, що на неї впливав C ++, але це неправда. Його головний вплив - Objective-C (і Smalltalk через це), і Java матиме набагато більше сенсу, коли ви будете ставитися до цього як Smalltalk з типами замість C ++ з GC.
Jörg W Mittag

3
@RobertHarvey: TClassце основна мовна особливість, яка потребує підтримки компілятора. Ви не можете "написати свій" без написання власної мови, а для .NET навіть цього було б недостатньо, оскільки об'єктна модель визначається CLR, а не окремими мовами. Це щось, що буквально повинно бути частиною самої основи .NET, або воно не може існувати.
Мейсон Уілер

4
Перш за все, я можу з повною впевненістю сказати, що .NET не був продуктом "Borland". Звідки я це знаю? Я був (досі є) частиною первинної основної команди, яка розробила Delphi. Я тісно співпрацював з Андерсом, Чаком, Гері та іншими. Звичайно, я впевнений, що ви це знаєте. Що стосується існування посилань на клас (як називають TClass та подібні конструкції) в .NET, швидше за все, вважалося непотрібним через існування багатої інформації, доступної для роботи в режимі часу. У Delphi на початку було набагато менше інформації про типи, а посилання на клас були компромісом.
Аллен Бауер

Відповіді:


5

.NET (CLR) був третім поколінням компонентної об'єктної моделі Microsoft (COM), яку в перші дні називали "COM + час виконання". Microsoft Visual Basic та ринок управління COM / ActiveX мали набагато більший вплив на конкретний вибір архітектурної сумісності CLR, ніж Borland Delphi. (Справді, той факт, що Delphi прийняв елементи управління ActiveX, безумовно, допомагав рости екосистемі ActiveX, але COM / ActiveX існував до Delphi)

Архітектура COM розроблялася на C (а не на C ++) і орієнтувалася на інтерфейси, а не на класи. Крім того, підтримується композиція об'єктів, що означає, що об'єкт COM насправді може складатися з декількох різних об'єктів, інтерфейс IUnknown пов'язує їх між собою. Але IUnknown не брав ніякої ролі в створенні об'єктів COM, який був розроблений таким чином, щоб бути максимально незалежним від мови. Створенням об'єктів, як правило, займалася IClassFactory, а відображенням через ITypeLibrary та пов'язані з ними інтерфейси. Цей розрив проблем не залежав від мови впровадження, і особливості кожного основного інтерфейсу COM були мінімальними та ортогональними.

Отже, внаслідок популярності керування COM та ActiveX, архітектура .NET була побудована для підтримки COM IUnknown, IClassFactory та ITypeLibrary. У COM ці інтерфейси не обов'язково були на одному об'єкті, тому об'єднувати їх разом не обов'язково має сенс.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.