.NET/C# для начинающих (Часть 2 — Что такое .NET)

В предыдущей заметке я рассказывал, как написать на языке C# консольную программу HelloWorld и графическую программу на основе библиотеки WPF. Я сразу начал с программирования, так как мне не хотелось начинать рассказ о платформе .NET с голой теории… которую я и изложу очень кратко в настоящей заметке. Основным источником вдохновения для меня служила книга Jeffrey Richter — CLR via C# — 2012.

Что такое .NET?

Это платформа для разработки приложений, которая состоит из двух частей: виртуальная машина (Common Language Runtime — CLR) + набор библиотек.

Зачем нужна платформа .NET?

Она решает ряд задач, которые всегда мучили разработчиков программного кода:

  • Кроссплатформенность. Разработчики хотят, чтобы программное обеспечение было переносимо на различные платформы на уровне двоичных файлов. Например Windows и Linux предоставляют прикладным программам различные программные интерфейсы (API), а кроме того в этих ОС используются разные форматы исполняемых файлов, поэтому программа, скомпилированная для Windows, не запустится в Linux и наоборот. С другой стороны возможна переносимость на уровне исходных кодов. Предположим вы пишете программу на языке C++. Если в исходном тексте своей программы вы пользуетесь только стандартными библиотеками языков C и C++, то вы можете скомпилировать программу отдельно для Windows и отдельно для Linux. Двоичные файлы будут разные, но зато исходный текст программы будет тот же самый. А вот если вы пишете программу на платформе .NET, то вам даже перекомпилировать программу под разные платформы не придется. Всё дело в том, что двоичный файл сборки содержит код не для Windows и не для Linux, а для CLR, а вот уже CLR транслирует его в код для Windows, Linux или другой конечной платформы. Двоичный код для CLR называется IL-код (IL означает Intermediate Language).
  • Самоописываемость. Повторно используемый программный код обычно распространяется либо в виде файлов исходного кода, либо в виде двоичных файлов. И то, и другое называют библиотеками. Предположим вы хотите в своем проекте на языке C/C++ использовать написанную кем-то библиотеку функций. Что вам для этого понадобится? Во-первых, двоичный файл библиотеки. Во-вторых — заголовочный файл с прототипами функций библиотеки — без него компилятор не будет знать, как вызвать эти функции. Сборки .NET избавляют нас от необходимости иметь заголовочные файлы. Файлы сборок .NET сами хранят ту информацию, которая должна была бы быть в заголовочных файлах. Эта информация называется метаданные. Программы могут читать метаданные во время своего выполнения при помощи API под названием Reflection. Например, программа может узнать, какие классы определены в той или иной библиотеке, какие у этих классов поля и методы, каков тип полей, каковы сигнатуры методов и прочее. Наличие метаданных решает такую задачу как Runtime Type Identification (RTTI).
  • Управляемый код. Тот факт, что двоичный IL-код в .NET (он называется управляемый код) выполняет виртуальная машина, плюс наличие метаданных — позволяет контролировать такие вещи, которые не смогла бы контролировать обычная невиртуальная машина. К ним относятся например выход за границу массива и преобразование типов (т. е. выход за границу массива или небезопасное преобразование типов в управляемом коде невозможно в принципе).
  • Language interoperability. Возможность взаимодействия между программными модулями, написанными на разных языках программирования. Программировать для платформы .NET можно на десятках разных языков программирования. Исходный код на всех этих языках транслируется в IL-код. Intermediate Language несмотря на то, что это машинный язык, является объектно-ориентированным. Вы можете например создать библиотеку классов на C# или Visual Basic, а в результате получится IL-код, который можно будет использовать в проектах на Ruby или Python.
  • Управление памятью. Многие приложения во время своей работы постоянно пользуются динамически выделяемой памятью (т. н. память из кучи). Когда динамически выделенная память перестает быть нужна, ее надо освобождать. Но определить, что память больше не нужна, не всегда легко. В C++ например динамическая память обычно используется для хранения объектов. Если объект не нужен, то его можно уничтожить (освободить занимаемую им память). Критерием нужности объекта является наличие ссылок на него. Следовательно надо отслеживать все ссылки на все объекты в куче. В C++ программист решает эту задачу, пользуясь различными «умными» указателями (smart pointers). В .NET за отслеживание ссылок на объекты и освобождение памяти отвечает виртуальная машина — ее компонент, называемый сборщик мусора. Поэтому программисту в .NET не нужно беспокоиться о возможных утечках памяти.
  • Безопасность. Допустим вы пользуетесь некой динамически подключаемой библиотекой, т. е. вызываете из нее некие функции. Представьте себе, что некий злоумышленник подменяет файл библиотеки своим файлом, который содержит вредоносный код. Понятно, к чему это приведет. Так вот: в .NET есть средства, которые позволяют однозначно идентифицировать файл сборки, так что подменить ее невозможно. Сборке можно присвоить т. н. строгое имя, которое состоит из обычного текстового имени сборки, номера версии и открытого ключа. Для всех файлов, из которых состоит сборка вычисляется хэш. Далее этот хэш шифруется при помощи закрытого ключа, доступ к которому есть только у владельца/разработчика сборки. Зашифрованный хэш может быть расшифрован при помощи открытого ключа, который находится в метаданных сборки и поэтому поставляется конечным пользователям. Когда CLR загружает сборку в память, она расшифровывает при помощи открытого ключа зашифрованный хэш и сравнивает его с вычисленным ею хэшем всех файлов сборки. Если они совпадают, значит сборка подлинная. Если злоумышленник подменил сборку, то у ее хэш будет отличаться от хэша подлинной сборки. Чтобы CLR признала поддельную сборку подлинной, злоумышленник должен так зашифровать хэш поддельной сборки, чтобы его можно было расшифровать открытым ключом подлинной сборки. Но сделать это он может только зная закрытый ключ, которым он не обладает, поэтому подменить подлинную сборку поддельной он не сможет.
  • DLL hell. Обычные не .NET’овские файлы динамически подключаемых библиотек в Windows идентифицируются только по имени файла библиотеки. Поэтому если файл каким-то образом будет заменен на новый (например, если разработчик библиотеки выпустит ее обновление или если пользователь установит на ПК библиотеку другого разработчика с таким же именем), то ПО, которое было написано и протестировано с исходной версией библиотеки может перестать функционировать. Эта проблема называется «ад DLL». В .NET однозначная идентификация сборок по строгому имени полностью решает эту проблему. Несмотря на то, что имена файлов каких-либо двух библиотек могут быть идентичны, их строгие имена уникальны. Сами же файлы хранятся в разных папках в специальном хранилище под названием Global Assembly Cache (GAC), поэтому один файл не затрет другой.
  • Расширяемость. В .NET вы программы могут во время своего выполнения загружать в память подключаемые модули и выполнять их код. Учитывая, что этот код потенциально может быть небезопасным, он запускается в «песочнице», которая называется AppDomain — домен приложения. Домену можно ограничить в правах, например запретить ему выполнять операции с файлами. Также домен можно выгрузить, освободив все занимаемые им ресурсы.

Платформы .NET Core, .NET Framework, Mono, Xamarin.Android, Xamarin.iOS и спецификация .NET Standard

Существует несколько различных реализаций виртуальной машины .NET и .NET’овских библиотек. Какие-то их них предназначены для конкретной платформы (.NET Framework, Xamarin.Android, Xamarin.iOS — для Windows, Android и iOS соответственно), какие-то — кроссплатформенные (.NET Core и Mono). Изначально все они реализовывали некоторое подмножество API, реализуемых .NET Framework. Затем Microsoft выпустила спецификацию API под названием .NET Standard стандарт, который должны были реализовывать все реализации платформы .NET. Наличие стандарта позволяет создавать кроссплатформенные библиотеки, и, вероятно, стоит это делать, если только вы не используете в своем проекте какой-нибудь некроссплатформенный API вроде WPF.

Библиотеки .NET Framework

Осталось сказать, что .NET Framework включает огромное количество библиотек на все случаи жизни. Перечислю основные известные мне:

  • Task Parallel Library (TPL)
  • Windows Presentation Foundation (WPF)
  • Windows Communication Foundation (WCF)
  • Windows Workflow Foundation
  • Active Servlet Pages (ASP.NET)
  • Visual Studio Tools for Office (VSTO)
  • ActiveX Data Object for .NET (ADO.NET)

Добавить комментарий

Ваш адрес email не будет опубликован.