Кратко съдържание



страница10/73
Дата21.07.2018
Размер9.03 Mb.
#76887
1   ...   6   7   8   9   10   11   12   13   ...   73

Какво е .NET Framework?


До момента направихме преглед на .NET платформата и разгледахме компонентите, от които тя се състои. Сега ще разгледаме в детайли .NET Framework, неговата архитектура и модела за изпълнение на приложения, който тя използва.

.NET Framework e среда за разработка и изпълнение на приложения за .NET платформата. Тя предоставя програмен модел, библиотеки от типове и единна инфраструктура за разработка на приложения и поддържа различни езици за програмиране.

Приложенията, базирани на .NET Framework, се компилират до междинен код (на езика IL) и се изпълня­ват контролирано от средата за изпълнение на .NET Framework. Компилираният .NET код се нарича още управляван код и може да работи без да се прекомпилира върху различни платформи, за които има имплементация за .NET Framework (Windows, Linux, FreeBSD).

Компоненти на .NET Framework


Можем да разделим .NET Framework на два основни компонента:

  • Common Language Runtime (CLR) – средата, в която се изпълнява управляваният код на .NET приложенията. Представлява виртуална машина, която контролирано изпълнява .NET кода и осигурява раз­лични услуги, като управление на сигурността, управление на паметта и др.

  • Framework Class Library (FCL) – представлява основната библио­тека от типове, които се използват при изграждането на .NET приложения. Съдържа основната функционалност за разработка, необходима за пове­чето приложения, като вход/изход, връзка с бази данни, работа с XML, изграждане на уеб приложения, използване на уеб услуги, изграждане на графичен потребителски интерфейс и др. Стандартните класове и типове от FCL можем да използваме нався­къде, където има инсталиран .NET Framework.

Архитектура на .NET Framework


Архитектурата на .NET Framework често пъти се разглежда на нива, както това е направено на следната схема:

Ще разгледаме отделните слоеве един по един и ще обясним тяхната роля в .NET Framework. Ще започнем от най-долния.


Операционна система


Операционната система управлява ресурсите, процесите и потребителите на машината. Тя предоставя и някои услуги на приложенията като например: COM+, MSMQ, IIS, WMI и други.

Средата, която изпълнява .NET приложенията (CLR), е обикновен процес в операционната система и се управлява от нея, както останалите процеси.

Най-често операционната система, която изпълнява CLR е Microsoft Windows, но .NET Framework има имплементации и за други операционни системи (например проектът Mono).

Common Language Runtime


Общата среда за изпълнение Common Language Runtime (CLR) управлява процеса на изпълнение на .NET код. Тя се грижи за заделяне и освобож­даване на паметта, управлява конкурентността, грижите за сигурността на приложенията и изпълнява други важни задачи, свързани с изпълнението на кода. Ще обърнем специално внимание на CLR малко по-нататък.

Base Class Library


Base Class Library (BCL) е част от стандартната библиотека на .NET Framework – Framework Class Library (FCL).

BCL представлява богата обектно-ориентирана библиотека с основни кла­сове, които осигуряват базова системна функционалност. BCL осигу­рява вход-изход, работа с колекции, символни низове, мрежови ресурси, сигурност, отдалечено извик­ване, многонишковост и др.

Технологиите ADO.NET, XML, ASP.NET и Windows Forms не са част от BCL, тъй като те са по-скоро допълнителни библио­теки, отколкото базова системна функционалност.

ADO.NET и XML


Слоят на ADO.NET и XML предоставя удобен начин за работа с релационни и други бази от данни и средства за обработка на XML. ADO.NET поддържа два моделa на работа с данни – свързан и несвързан. XML поддръжката реализира DOM модела и модел, подобен на SAX, за достъп до XML. Ще разгледаме в детайли XML и ADO.NET в темите "Работа с XML" и "Достъп до данни с ADO.NET".

ASP.NET и Windows Forms


ASP.NET и Windows Forms изграждат слоя за интерфейс към крайния пот­ре­бител на приложенията и ни предоставят богата функционалност за създаване на уеб и Windows базиран потребителски интерфейс, както и уеб услуги. ASP.NET позво­лява по лесен начин да бъдат изграждани гъв­кави динамични уеб сайтове и уеб приложения и уеб услуги. Windows Forms позволява изграждане на прозоречно-базиран графичен потреби­телски интерфейс с богати възмож­ности.

ASP.NET и Windows Forms използват компонентно-базирана архитектура и благодарение на нея позволяват изграждане на потребителския интер­фейс визуално, чрез сглобяване на компоненти в специално разработени за това редактори, предоставени от средите за разработка. Ще разгле­даме в детайли технологиите Windows Forms и ASP.NET в темите "Графи­чен потребителски интерфейс с Windows Forms", "Изграждане на уеб приложения с ASP.NET" и "Уеб услуги с ASP.NET".


Езици за програмиране


.NET Framework позволява на разработчика да използва различни езици за програми­ране, както и да интегрира в едно приложение компоненти, разработвани на различни езици. Възможно е дори клас, написан на един език, да бъде наследен и разширен от клас, написан на друг език.

Microsoft .NET Framework поддържа стандартно езиците C#, VB.NET, Managed C++ и J#, но трети доставчици предлагат допълнително .NET версия на още много други езици, като Pascal, Perl, Python, Fortran, Cobol и други.

Съвместимостта на езиците за програмиране в .NET Framework се дължи на архитектурни решения, които ще разгледаме в детайли след малко.

Common Language Runtime


След като се запознахме накратко с архитектурата на .NET Framework, нека сега разгле­даме в детайли и най-важният компонент от нея – CLR.

Common Language Runtime (CLR) е сърцето на .NET Framework. Той пред­ставлява среда за контролирано изпълнение на управляван код. На практика CLR е тази част от .NET Framework, която изпълнява компили­раните .NET програми в специална изолирана среда.

В своята същност CLR представлява виртуална машина, която изпълнява инструкции, на езика IL (Intermediate Language), езикът до който се компилират всички .NET езици. CLR е нещо като виртуален компютър, който обаче не изпълнява асемблерен код за процесор Pentium, AMD или някакъв друг, а IL код.

Има голямо сходство между .NET CLR и Java Virtual Machine, но между двете технологии и много разлики. По предназначение те служат за едно също нещо – да изпълняват код за някакъв виртуален процесор. В .NET това е IL кода, а при Java платформата – т. нар. Java bytecode. Основната разлика между IL и bytecode е, че IL е език от по-високо ниво, а това позволява да бъде компилиран много по-ефективно от Java bytecode.


Задачи и отговорности на CLR


Отговорностите на CLR включват:

  • Изпълнение на IL кода. Реално IL инструкциите, преди да бъдат изпълнени за първи път, се компилират до инструкции за текущия процесор и след това се изпълняват от системния процесор. Този процес на междинно компилиране до машиннозависим (native) код се нарича JIT компилация (Just-In-Time compilation).

  • Управление на паметта и ресурсите на приложенията. CLR включва в себе си система за заделяне на памет и система за почистване на неизползваната памет и ресурси (т. нар. garbage collector). Управ­лението на паметта при .NET приложенията се извършва в голяма степен авто­матизирано и в повечето случаи програмистът не трябва да се грижи за освобождаване на заделената памет. Ще разгледаме в детайли как .NET Framework управлява паметта в темата "Управ­ление на паметта и ресурсите".

  • Осигуряване безопасността на типовете. .NET Framework е среда за контролирано изпълнение на програмен код (managed execution environment). Тя не позволява директен достъп до паметта, не позволява директна работа с указатели, не позволява преобразуване от един тип към друг, който не е съвмес­тим с него, не позволява излизане от границите на масив, както и всякакви други опасни операции. По тази причина .NET се нарича управля­вана среда – защото тя управлява изпълнението на кода и по този начин предпазва програмите от много досадни проблеми, които възникват при неуправляваните среди.

  • Управление на сигурността. NET Framework има добре изградена концеп­ция за сигурност на различни нива. От една страна .NET приложенията могат да се изпълняват с различни права. Правата могат да се задават от администраторите чрез т. нар. политики за сигур­ност. CLR следи дали кодът, който се изпълнява, спазва зада­дената политика за сигурност и не позволява тя да бъде нарушена. Тази техника се нарича "code access security". От друга страна .NET Framework поддържа и средства за управление на сигурността, бази­рана на роли (role-based security). Ще разгледаме в детайли всички тези техники и средства в темата "Сигурност в .NET Framework".

  • Управление на изключенията. .NET Framework е изцяло обектно-ориен­тирана среда за разработка и изпълнение на програмен код. В нея механизмът на изключенията е залегнал като основно средство за управление на грешки и непредвидени ситуации. Една от зада­чите на CLR е да се грижи за изключенията, които възникват по време на изпълнение на кода. При настъпване на изключение CLR има грижата да намери съответния обработчик и да му предостави управлението. Ще разгледаме в детайли всичко това в темата "Управление на изключенията в .NET".

  • Управление на конкурентността. CLR контролира паралелното изпълнението на нишки (threads) като за целта си взаимодейства с операци­онната система. Повече за работата с нишки ще научим в темата "Многонишково програмиране и синхронизация".

  • Взаимодействие с неуправляван код. CLR осигурява връзка между управляван (.NET) код и неуправляван (Win32) код. За целта той изпълнява доста сложни задачи, свързани с конвертиране на данни, синхронизация, прехвърляне на извиквания, взаимодействие с компонентния модел на Windows (COM) и много други. Ще разгле­даме в детайли тези проблеми в темата "Взаимодействие с неуправ­ляван код".

  • Подпомагане процесите на дебъгване (debugging) и оптими­зиране (profiling) на управлявания код. CLR осигурява инфра­структура и средства за реализацията на дебъгване и оптими­зиране на кода от външни специализирани програми.

Управляван код


Управляваният код (managed code) е кодът, който се изпълнява от CLR. Той представлява поредица от IL инструкции, които се получават при компилацията на .NET езиците. По време на изпълнение управлява­ният код се компилира допълнително до машиннозависим код за текущата платформа и след това се изпълнява директно от процесора.

Управляван код и неуправляван код


Управляваният код (.NET код) се различава значително от неуправля­вания код (например Win32 кода).

Управляваният код е машиннонеза­висим, т. е. може да работи на различ­ни хардуерни архитектури, проце­сори и опера­ционни системи, стига за тях да има имплементация на CLR.



Неуправ­лява­ният код е машиннозависим, компилиран за определена хардуерна архи­тектура и определен процесор. Например програмите, написани на езика C, се компилират до неуправляван код за определена архитектура.

Ако компилираме една C програма за Embedded Linux върху плат­форма StrongARM, ще получим неуправляван машиннозависим (native) код за Linux за тази платформа. Кодът ще съдържа инструкции за мик­ропро­цесор StrongARM и ще използва системни извиквания към операци­онната система Embedded Linux. Съответно на друга платформа няма да може да работи без прекомпилация на сорс кода на C програмата.

По същия начин, ако компилираме една C програма за Windows върху архитектура x86, ще получим неуправляван код за процесор x86 (при­мерно Pentium, Athlon и т.н.), който използва системни извиквания към Windows. Този код се нарича Win32 код и може да работи само върху 32-битова Windows операционна система. За да се стартира върху друга платформа, трябва да се компилира.

При управлявания код нещата стоят по различен начин. Ако компилираме една C# програма за платформа .NET Framework 1.1, ще получим управ­ляван, машиннонезависим IL код, който може да работи върху разли­чен хардуер. Кодът реално ще е компилиран за платформа CLR 1.1 и ще се състои от IL инструкции за виртуалния процесор на CLR и ще използва системни извиквания към .NET Base Class Library.

Управляваният код лесно може да бъде пренесен върху различни плат­форми без да се променя или прекомпилира. Така например програма на C#, която е компилирана под Windows до управляван IL код, може да се изпълнява без промени както върху Windows под .NET Framework, така и върху Linux под Mono, а също и върху мобилни устройства под Windows CE и .NET Compact Framework.

Метаданните в управлявания код


Управляваният код се самоописва чрез метаданни и носи в себе си опи­сание на типове данни, класове, интерфейси, свойства, полета, методи, пара­метри на мето­дите и други, както и описание на библиотеки с типове, описание на изисквания към сигурността при изпълнение и т. н. Това дава голяма гъвкавост на разработчика и възмож­ност за динамично зареждане, изследване и изпълнение на функционалност, компилирана като управля­ван (IL) код.

Неуправляваният код стандартно не съдържа метаданни и това силно затруднява динамичното зареждане и изпълнение на неуправлявана функционалност.


Управляваният код е обектно-ориентиран


Управляваният код задължително е обектно-ориентиран, докато за неуп­равлявания няма такова изискване. Всички .NET езици са обектно-ориентирани. Всички .NET програми се компилират до класове и други типове от общата система от типове на .NET Framework. Всички данни, използвани от управлявания код, са наследници (в смисъла на обектно-ориентираното програмиране) на базовия тип System.Object. Ще разгле­даме това в подробности в темата "Обща система от типове".

Управляваният код е високо надежден


Управляваният код е защитен от неправилна работа с паметта и типо­вете и това го прави по-сигурен и високо надежден. Управляваният код не може да извършва неправилен достъп до паметта, достъп до чужда памет и неправилна работа с типове. Това предпазва програмисти от много досадни проблеми, присъщи при писането на неуправляван код, като загуба на памет, достъп до неинициализирана памет, повторно осво­бождаване на памет, работа с невалиден указател и т.н.

Управляваният код интегрира различни езици


До управляван код се компилират всички .NET езици. Това дава възмож­ност за широко взаимодействие между код, писан на различни езици за програмиране. Възможно е дори клас, написан на един .NET език, да бъде наследен и разширен от клас, написан на друг .NET език.

За .NET Framework няма значение на какъв език е бил написан кода преди да бъде компилиран. Всичкият код се компилира до IL и се изпълнява от CLR по еднакъв начин.


Управление на паметта


Управлението на паметта е една от важните задачи на CLR. Идеята за автоматизирано управление на паметта е залегнала в .NET Framework на дълбоко архитектурно ниво. Целта е да се улесни разработчика като се освободи от досадната задача сам да следи за освобождаването на заделената памет.

CLR, като средата за изпълнение, управлява заделянето на памет, иници­ализирането й, и автоматичното й освобождаването посредством garbage collector.

Динамично заделените обекти се разполагат в динамичната памет, в тъй наречения "managed heap". След като техния живот завърши и те вече не са необходими на приложението, системата за почистване на паметта (garbage collector) освобождава заеманата от тях памет автоматично. По този начин се избягват най-често срещаните проблеми като загуба на памет и достъп до освободена или неинициализирана памет. Повече за управлението на паметта в .NET Framework ще научим в темата "Управление на паметта и ресурсите".

Важна особеност при работата с управляван код е, че при него няма указатели. Вместо указатели се работи с референции, които са силно типизирани и се управляват автоматично. Референцията (reference) прилича на указател, но не е просто адрес в паметта, а има тип, т. е. тя е указател към определен тип данни и не може да сочи към място в паметта, където няма инстанция на този тип.


Intermediate Language (IL)


Междинният език Intermediate Language (IL), е език за прог­рамиране от ниско ниво, подо­бен на асемблерните езици. За разлика от тях, обаче, IL е от много по-високо ниво, отколкото асемблерите за съвременните мик­ропроцесори.

IL е обектно-ориентиран език. Той разполага с инструкции за заделяне на памет, за създаване на обект, за предизвикване и обработка на изклю­чения, за извикване на виртуални методи и други инструкции, свързани с обектно-ориентираното програмиране.

Тъй като не е процесорно-специфичен, IL предос­тавя голяма гъвкавост и възможност за изпълнение на кода върху различни платформи чрез компилиране до съответния за платформата машинен език.

Възможна е и предварителна компилация до код за текущата платформа, но тази техника не носи голяма полза и рядко се използва.

Имплементацията на IL в .NET Framework се нарича MSIL (Microsoft Intermediate Language). IL може да има и други имплементации в други платформи и среди за изпълнение на .NET код.

Езикът IL е стандартизиран от организацията ECMA и в съответния стан­дарт се нарича CIL (Common Intermediate Language).





Често пъти термините IL и MSIL се използват като взаи­мозаменяеми и затова винаги трябва да имате предвид, че става въпрос за кода, който се изпълнява от CLR – ма­шинният код, получен при компилацията на .NET езиците.

Intermediate Language (IL) – пример


За да илюстрираме по-добре казаното до тук, нека разгледаме една проста програмка, написана на MSIL – класическият пример "Hello world!":

.method private hidebysig static void Main() cil managed

{

.entrypoint

// Code size 11 (0xb)

.maxstack 8

ldstr "Hello, world!"

call void [mscorlib]System.Console::WriteLine(string)

ret

} // end of method HelloWorld::Main

Всичко, което прави тази MSIL програма, е да изведе съобщението "Hello, world!" на конзолата. Тя дефинира един статичен метод без параметри с име Main, в който извиква с параметър "Hello, world!" статичния метод WriteLine() от класа System.Console, който отпечатва посочения текст.

Компилация и изпълнение


Вече споменахме няколко пъти междинния код IL и обяснихме, че .NET езиците (C#, VB.NET и т. н.) се компилират до него, а след това получе­ният код се изпълнява от CLR.

Сега ще разгледаме детайлно процеса на компилиране и изпълнение на .NET приложенията. Ще изясним как се извършва компилирането на програми от високо ниво, как се получава IL код, как този код се записва в специален файлов формат (асембли) и как след това компилираните асемблита се изпълняват от CLR като се компилират междувременно до машинен код от JIT компилатора.

Целият този процес е изобразен схематично на фигурата:

Изходният код на .NET програмите може да е написан на предпочитания от нас .NET език, например C#, VB.NET, Managed C++ или друг. За да го компилираме до IL управляван код, използваме компилатора за съответ­ния език. В резултат получаваме асембли.



Асемблито представлява изпълним файл, съдържащ .NET управляван код и метаданни, които описват съдържанието на асемблито. Метаданните съдържат имената на класовете и типовете в асемблито, информация за членовете на класовете (методи, полета, свойства и други).

Едно асембли може да бъде изпълним файл (.exe файл) или динамична библиотека (.dll файл). Изпълнимите файлове съдържат допълнителна информация, която подпомага началното им стартиране (например входна точка на изпълнение).

При изпълнение на дадено асембли CLR го зарежда в паметта и анализира метаданните му. Извършват се различни проверки на кода – дали е коректен спрямо IL стандарта, дали има необходимите права за изпъл­нение и др.

След това управляваният IL код преминава през специфичния за текущата платформа JIT компилатор и се компилира до машинен код за текущия процесор. Компилираният вече код след това се изпълнява директно от процесора.

JIT компилаторът не компилира в началото цялото асембли, а само методът, от който започва изпълнението му. След това при опит за изпълнение на некомпилиран метод, той се компилира. Така кодът се компилира само при нужда и това осигурява добро бързодействие. Забавянето е незначително и скоростта на изпълнение на управлявания код на практика е почти еднаква със скоростта на изпълнение на неуправлявания код.

Предимството на JIT компилацията е, че може да оптимизира кода за текущата хардуерна платформа по най-добрия начин. Например ако е наличен най-мощният процесор на Intel или AMD и CLR поддържа този процесор, той ще компилира IL кода по начин, оптимизиран специално за него, и ще използва пълните му възможности. При неуправляваният код това не е възможно, защото кодът се компилира така, че да работи върху всички процесори, без да използва пълните възможности на текущата хардуерна платформа. По тази причина в някои случаи управляваният код може да е дори по-бърз от неуправлявания въпреки нуждата от JIT компилация, която отнема време.

Когато разполагаме с компилирано асембли и искаме да го изпълним, имаме право на избор кога да компилираме IL кода до машинен код. Това може да стане по време на изпълнение (посредством JIT компилатора) и предварително (с прекомпилация за текущата платформа).

Прекомпилацията на асемблита се извършва с инструмента ngen.exe, който е стандартна част от .NET Framework.


Архитектура на CLR


Общата среда за изпълнение CLR се състои от доста модули, всеки от които изпълнява конкретна задача. Схематично архитектурата можем да представим по следния начин:

Ще разгледаме всеки от посочените компоненти съвсем накратко, тъй като функциите им са от много ниско ниво и рядко ще ни се налага да взаимодействаме директно с тях:



  • Base Class Library Support – предоставя системни услуги, необходими за работата на Base Class Library (BCL).

  • Thread Support – предоставя услуги за манипулация на нишки в .NET приложенията – създаване на нишка, управление на състоянието на нишка, синхронизация и др.

  • COM Marshaler – грижи се за комуникацията с COM обекти. Осигу­рява извикването на COM сървъри от .NET код и извикването на .NET код от COM. Негова грижа са прехвър­лянето на заявки, преобра­зуването на данни, управлението на жизнения цикъл на COM обектите и др.

  • Type Checker – осъществява проверка на типовете за съответствие при извикване и поддържа класовите йерархии.

  • Exception Manager – грижи се за управление на изключенията –предизвикване на изключение, прихващане, обработване и др.

  • Security Engine – отговаря за проверките на сигурността при изпъл­нение на кода.

  • Debug Engine – осигурява функционалност, свързана с дебъгването и оптимизирането на управляван код.

  • JIT Compiler – един от най-важните модули – по време на изпъл­нение компилира IL кода в специфичен за процесора код.

  • Code Manager – управлява изпълнението на кода.

  • Garbage Collector – управлява паметта автоматичното почистване на паметта и ресурсите. Контролира живота на обектите.

  • Class Loader – служи за зареждане на класове и типове. Използва се при началното изпълнение на приложението, както и при динамично зареждане на код по време на изпълнение.

Как CLR изпълнява IL кода?


Нека сега разгледаме по-подробно как CLR изпълнява IL кода. Изпълне­нието на кода, както можем да видим от схемата по-долу, е итеративен процес, който се състои от много стъпки.

При изпълнение на метод от едно асембли Class Loader подсистемата на CLR зарежда всички нужни за неговата работа класове и типове. В зависимост от това дали кодът е вече компилиран до машинен или не Class Loader предава кода за директно изпълнение или го компилира с JIT компила­тора (при първо извикване на всеки метод).



Преди JIT компилацията се извършва процес, известен като верификация. Той проверява дали IL кодът е безопасен – дали не се опитва да осъществява директен достъп до паметта, дали не се опитва да заобикаля механизмите за сигурност и т. н. Ако системният администратор е определил кода за сигурен (trusted) неговото верифициране може да бъде се прескочено.

JIT компилаторът създава специфичен за машината код (native код), който се изпъл­нява директно от процесора. Този машинен код съдържа в себе си много допълнителни инструкции, чрез които си взаимодейства със CLR. Целта е кодът да се изпълнява по контролиран начин, за да не нарушава принципите за сигурност и надеждност, но без да се забавя излишно заради всички допълнителни проверки.

При изпълнението на кода, при достъп до ресурси, при извикване на системни библиотеки и в много други случаи се извършват проверки на сигурността (чрез т. нар. security engine).

Ако трябва да бъде извикан некомпилиран метод, този метод се връща в JIT компилатора и така се затваря цикълът на компилация до машинен код. Като резултат от описания алгоритъм не се налага компилиране на един и същ метод повече от веднъж и освен това, ако някой метод не се извиква никъде в приложението, той въобще не се компилира от JIT компилатора.




Сподели с приятели:
1   ...   6   7   8   9   10   11   12   13   ...   73




©obuch.info 2024
отнасят до администрацията

    Начална страница