Тем, кто знаком с историей, хорошо известно, что C # и .NET Framework начинались как «Delphi, переписанный для ощущения Java», созданный главным разработчиком Delphi Андерсом Хейлсбергом. С тех пор все немного изменилось, но на самом деле сходство было настолько очевидным, что даже были серьезные предположения, что .NET изначально был продуктом Borland.
Но в последнее время я изучал некоторые вещи .NET, и одна из самых интересных и полезных функций Delphi, похоже, полностью отсутствует: концепция классов как первоклассного типа данных. Для тех, кто не знаком с ним, тип TClass
представляет ссылку на класс, похожий на Type
тип в .NET. Но где .NET использует Type
для отражения, Delphi использует TClass
в качестве очень важной встроенной части языка. Он учитывает различные полезные идиомы, которые просто не существуют и не могут существовать без него, такие как переменные подтипов классов и методы виртуальных классов.
Каждый ОО-язык имеет виртуальные методы, в которых разные классы по-разному реализуют одну и ту же фундаментальную концепцию метода, а затем во время выполнения вызывается правильный метод на основе фактического типа экземпляра объекта, к которому он обращен. Delphi распространяет эту концепцию на классы: если у вас есть ссылка на TClass, определенная как определенный подтип класса (то есть class of TMyClass
означает, что переменная может принимать любую ссылку на класс, которая наследуется TMyClass
, но не что-либо вне иерархии), к которой присоединены виртуальные методы области класса это, они могут быть вызваны без экземпляра, используя фактический тип класса. Например, применение этого шаблона к конструкторам делает реализацию Factory тривиальной.
Кажется, в .NET нет ничего эквивалентного. Как полезны ссылки на классы (особенно на виртуальные конструкторы и другие методы виртуальных классов!), Кто-нибудь говорил что-нибудь о том, почему они были исключены?
Конкретные примеры
Форма десериализации
Delphi VCL сохраняет формы в DFM
формате, DSL для описания иерархии компонентов. Когда средство чтения форм анализирует данные DFM, оно наталкивается на объекты, которые описаны следующим образом:
object Name: ClassName
property = value
property = value
...
object SubObjectName: ClassName
...
end
end
Интересная вещь здесь - ClassName
часть. Каждый класс компонента регистрирует его TClass
в системе потоковой передачи компонента initialization
одновременно (представьте, что статические конструкторы, только немного отличающиеся, гарантированно произойдут сразу при запуске). Это регистрирует каждый класс в хеш-таблице string-> TClass с именем класса в качестве ключа.
Каждый компонент происходит от TComponent
, у которого есть виртуальный конструктор, который принимает один аргумент Owner: TComponent
. Любой компонент может переопределить этот конструктор, чтобы обеспечить собственную инициализацию. Когда читатель DFM читает имя класса, он ищет имя в вышеупомянутой хэш-карте и получает соответствующую ссылку на класс (или вызывает исключение, если его там нет), а затем вызывает для него виртуальный конструктор TComponent, который, как известно, является хорошим потому что функция регистрации принимает ссылку на класс, которая требуется для наследования от TComponent, и в результате вы получаете объект соответствующего типа.
Без этого, WinForms-эквивалент - это ... ну ... большой беспорядок, если говорить прямо, требуя, чтобы любой новый язык .NET полностью заново реализовывал свою собственную форму (де) сериализацию. Это немного шокирует, когда вы думаете об этом; Поскольку весь смысл наличия CLR состоит в том, чтобы позволить нескольким языкам использовать одну и ту же базовую инфраструктуру, система в стиле DFM имела бы смысл.
растяжимость
Класс менеджера изображений, который я написал, может быть снабжен источником данных (например, путем к файлам изображений), а затем автоматически загружать новые объекты изображений, если вы пытаетесь получить имя, которого нет в коллекции, но которое доступно в источнике данных. Он имеет переменную класса, типизированную как class of
базовый класс изображения, представляющий класс любых новых создаваемых объектов. Он поставляется по умолчанию, но есть некоторые моменты при создании новых изображений со специальными целями, что изображения должны быть настроены по-разному. (Создание его без альфа-канала, получение специальных метаданных из файла PNG для указания размера спрайта и т. Д.)
Это может быть сделано путем написания большого количества кода конфигурации и передачи специальных параметров всем методам, которые могут в конечном итоге создать новый объект ... или вы можете просто создать подкласс базового класса изображений, который переопределяет виртуальный метод, где рассматриваемый аспект настраивается, а затем с помощью блока try / finally временно заменяет свойство «класс по умолчанию», а затем восстанавливает его. Делать это со ссылочными переменными класса гораздо проще, и это не то, что можно сделать с помощью обобщений.
TClass
полезно, с некоторым примером кода? В моем беглом интернет-исследовании TClass
я обнаружил, что это TClass
можно передать как параметр. Это делается в .NET с использованием Generics. Методы фабрики просто помечены static
в .NET и не требуют экземпляра класса для выполнения.
TClass
фундаментальная языковая функция, требующая поддержки компилятора. Вы не можете «написать свой собственный», не написав свой собственный язык, и для .NET даже этого будет недостаточно, поскольку объектная модель определяется CLR, а не отдельными языками. Это то, что буквально должно быть частью самой платформы .NET, иначе оно не может существовать.