2. Въведение в. Net среда net framework архитектура. Поддържане на единна езикова среда



страница3/4
Дата07.08.2017
Размер0.51 Mb.
#27470
1   2   3   4

36. Финализация в .NET среда.

Какво е финализация?

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

даден обект, преди обектът да бъде унищожен от garbage collector.

Обяснено най-просто, това е начин да се каже на CLR "преди този обект

да бъде унищожен, трябва да се изпълни ето този код".

За да е възможно това, класът трябва да имплементира специален метод,

наречен Finalize(). Когато garbage collector установи, че даден обект

вече не се използва от приложението, той проверява дали обектът

дефинира Finalize() метод. Ако това е така, Finalize() се изпълнява и

на по-късен етап (най-рано при следващото преминаване на garbage

collector), обектът се унищожава. Този процес ще бъде разгледан детайл-

но след малко. Засега просто трябва да запомните две неща:

- Finalize() не може да се извиква явно. Този метод се извиква

само от системата за почистване на паметта, когато тя прецени, че

даденият обект е отпадък.

- Най-малко две преминавания на garbage collector са необходими за

да се унищожи обект, дефиниращ Finalize() метод. При първото се

установява че обектът подлежи на унищожение и се изпълнява

финализаторът, а при второто се освобождава и заетата от обекта

памет. Всъщност в реалния живот почти винаги са необходими

повече от две събирания на garbage collector поради преминаването

на обекта в по-горно поколение.



37 Модел на явна финализация в .NET среда.Интегриране на Finalize() и Dispose()

Когато се създава нов обект, CLR проверява дали типът дефинира



Finalize() метод и ако това е така, след създаването на обекта в дина-

мичната памет (но преди извикването на неговия конструктор), указател

към обекта се добавя към Finalization list. Така Finalization list съдържа

указатели към всички обекти в хийпа, които трябва да бъдат финализи-

рани (имат Finalize() методи), но все още се използват от приложението

(или вече не се използват, но още не са проверени от garbage collector).



Създаването на обект, поддържащ финализация изисква

една допълнителна операция от страна на CLR – поста-

вянето на указател във Finalization list и следователно

отнема и малко повече време.

Взаимодействието на garbage collector с обектите, нуждаещи се от фина-

лизация, е твърде интересно. Нека разгледаме следния пример.

Фигурата по-долу показва опростена схема на състоянието на динамич-

ната памет точно преди да започне почистване на паметта. Виждаме че

хийпът съдържа три обекта – A, B и C. Нека всички те са от Поколение 0.

Обект A все още се използва от приложението, така че той ще оцелее при

преминаването на garbage collector. Обекти B и C, обаче, са недостъпни от

корените и се определят от garbage collector-a като отпадъци.

И така, garbage collector първо определя обект B като недостъпен и

следователно – подлежащ на почистване. След това указателят към обект

B се изтрива от Finalization list и се добавя към опашката Freachable. В

този момент обектът се съживява, т.е. той се добавя към графа на

достъпните обекти и вече не се счита за отпадък. Garbage collector

пренарежда динамичната памет. При това обект B се третира както всеки

друг достъпен от приложението обект, в нашия пример – обект A.

След това CLR стартира специална нишка с висок приоритет, която за

всеки запис във Freachable queue изпълнява Finalize() метода на съот-

ветния обект и след това изтрива записа от опашката.

При следващото почистване на Поколение 1 от garbage collector, обект B

ще бъде третиран като недостъпен (защото записът вече е изтрит от Freachable queue и никой от корените на приложението не сочи към

обекта) и паметта, заемана от него ще бъде освободена. Забележете, че

тъй като обектът вече е в по-високо поколение, преди това да се случи е

възможно да минат още няколко преминавания на garbage collector,

Интерфейсът IDisposable се препоръчва от Microsoft в тези случаи, в

които искате да га51.NET Framework и системата за управление на общи типове. Типовете в CLR.

CLR поддържа много езици за програмиране. За да се осигури съвмес-тимост на данните между различните езици е разработена общата система от типове (Common Type System – CTS). CTS дефинира поддържаните от CLR типове данни и операциите над тях. Всички .NET езици използват типовете от CTS. За всеки тип в даден .NET език има някакво съответствие в CTS, макар че понякога това съответ-ствие не е директно. Обратното не е вярно – съществуват CTS типове, които не се поддържат от някои .NET езици. По идея всички езици в .NET Framework са обектно-ориентирани. Common Type System също се придържа към идеите на обектно-ориентираното програмиране (ООП) и по тази причина описва освен стандартните типове (числа, символи, низове, структури, масиви) и някои типове данни свър-зани с ООП (например класове и интерфейси).

Типовете данни в CTS биват най-разнообразни:

- примитивни типове (primitive types – int, float, bool, char, …)

- изброени типове (enums)

- класове (classes)

- структури (structs)

- интерфейси (interfaces)

- делегати (delegates)

- масиви (arrays)

- указатели (pointers)


Всички тези типове повече или по-малко вече са ни познати от езика C#, но всъщност те са част от CTS. Езикът C# и другите .NET езици използват CTS типовете и им съпоставят запазени думи съгласно своя синтаксис. Например типът System.Int32 от CTS съответства на типа int в C#, а типът System.String – на типа string.рантирате моментално освобождаване на ресурсите (вече знаете, че използването на Finalize() не го гарантира). Използването на IDisposable се състои в имплементирането на интерфейса от класа, който обвива някакъв неуправляван ресурс и освобождаването на ресурса при извикване на метода Dispose().n

52.Стойностни типове. Стандартни и user-defined.

Стойностни и референтни типове

В CTS се поддържат две основни категории типове: стойностни типове (value types) и референтни типове (reference types). Стойностните типове съдържат директно стойността си в стека за изпълнение на прог-рамата, докато референтните типове съдържат строго типизиран указател (референция) към стойността, която се намира в динамичната памет. По- нататък ще разгледаме подробно разликите между стойностните и рефе- рентните типове и особеностите при тяхното използване.



Стойностни типове (value types)

Стойностни типове (типове по стойност) са повечето примитивни типове (int, float, bool, char и др.), структурите (struct в C#) и изброените типове (enum в C#).

Стойностните типове директно съдържат стойността си и се съхраняват физически в работния стек за изпълнение на програмата. Tе не могат да приемат стойност null, защото реално не са указатели.

Стойностните типове и паметта

Стойностните типове заемат необходимата им памет в стека в момента на декларирането им и я освобождават в момента на излизане от обхват (при достигане на края на програмния блок, в който са декларирани). Заде-лянето и освобождаване на памет за стойностен тип реално се извършва чрез единично преместване на указателя на стека и следователно става много бързо.

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

Стойностните типове наследяват System.ValueType

CLR се грижи всички стойностни типове да наследяват системния тип System.ValueType. Всички типове, които не наследяват ValueType са референтни типове, т.е. реално са указатели към динамичната памет (адреси в паметта).



Предаване на стойностни типове

При извикване на метод стойностните типове се подават по стойност, т.е. предава се копие от тях. При подготовка на извикването на метод CLR копира подаваните като параметри стойностни типове от оригиналното им местоположение в стека на ново място в стека и подава на извиквания метод направените копия. Ако извикваният метод промени стойността на подадения му по стойност параметър, при връщане от извикването про-мяната се губи. Това поведение важи, разбира се, само ако параметрите се подават по подразбиране, без да се използват ключовите думи в C# ref и out, които ще разгледаме по-нататък в следващите теми.



54.Събития. Кратък пример.

Събитията могат да се разглеждат като съобщения за настъпване на някакво действие. В компонентно-ориентираното програмиране компонен-тите изпращат събития (events) към своя притежател за да го уведомят за настъпването на интересна за него ситуация. Този модел е много характе-рен например за графичните потребителски интерфейси, където контро-лите уведомяват чрез събития други класове от програмата за действия от страна на потребителя. Например, когато потребителят натисне бутон, бутонът предизвиква събитие, с което известява, че е бил натиснат. Раз-бира се, събития могат да се предизвикват не само при реализиране на потребителски интерфейси. Нека вземем за пример програма, в която като част от функционалността влиза трансфер на файлове. Приключването на трансфера на файл може да се съобщава чрез събитие.

Изпращачи и получатели

Обектът, който предизвиква дадено събитие се нарича изпращач на събитието (event sender). Обектът, който получава дадено събитие се нарича получател на събитието (event receiver). За да могат да получават дадено събитие, получателите му трябва преди това да се абонират за него (subscribe for event).

За едно събитие могат да се абонират произволен брой получатели. Изпращачът на събитието не знае кои ще са получателите на събитието, което той предизвиква. Затова чрез механизма на събитията се постига по-ниска степен на свързаност (coupling) между отделните компоненти на програмата.

Събитията в .NET Framework

В компонентния модел на .NET Framework абонирането, изпращането и получаването на събития се поддържа чрез делегати и събития. Реализа-цията на механизма на събитията е едно от главните приложения на делегатите. Класът, който публикува събитието, дефинира делегат, който абонатите на събитието трябва да имплементират. Когато събитието бъде предизвикано, методите на абонатите се извикват посредством делегата. Тези методи обикновено се наричат обработчици на събитието. Делега-тът е multicast делегат, за да могат чрез него да се извикват много обра-ботващи методи (на всички абонати).

Извикването на събитие може да стане само в класа, в който то е дефинирано. Това означава, че само класът, в който се дефинира събитие, може да предизвика това събитие. Това е наложително, за да се спази шаблонът на Публикуващ/Абонати – абонираните класове се информират при промяна на състоянието на публикуващия и именно публикуващият е отговорен за разпращане на съобщенията за промяната, настъпила у него.

55.Проектиране на тип, предлагащ събитие. Проектиране на тип, използващ събитие. Същността на нещата.





56.Пакетирани типове (boxed types). Проблеми с достъпа.

Sтойностните типове се съхраняват в стека на прило-жението и не могат да приемат стойност null, докато референтните типове съдържат указател (референция) към стойност в динамичната памет и могат да бъдат null.

Понякога се налага на референтен тип да се присвои обект от стойностен тип. Например може да се наложи в System.Object инстанция да се запише System.Int32 стойност. CLR позволява това благодарение на т. нар. "опаковане" на стойностните типове (boxing).

В .NET Framework стойностните типове могат да се използват без преобразуване навсякъде, където се изискват референтни типове. При нужда CLR опакова и разопакова стойностните типове автоматично. Това спестява дефинирането на обвиващи (wrapper) класове за примитивните типове, структурите и изброените типове, но разбира се, може да доведе и до някои проблеми, които ще дискутираме по-късно.



Опаковане (boxing) на стойностни типове

Опаковането (boxing) е действие, което преобразува стойностен тип в рефере

нция към опакована стойност. То се извършва, когато е необхо-димо да се преобразува стойностен тип към референтен тип, например при преобразуване на Int32 към Object: int i = 5;

object obj = i; // i се опакова
Особености при опаковането и разопаковането

При използване на автоматично опаковане и разопаковане на стойности трябва да се имат предвид някои особености:

- Опаковането и разопаковането намаляват производителността. За оптимална производителност трябва да се намали броят на опако- ваните и разопакованите обекти.

- Опакованите типове са копия на оригиналните стойности, поради което, ако променяме оригиналния неопакован тип, опакованото копие не се променя.


При работа с опаковани обекти трябва да се внимава, защото ако не бъдат съобразени някои особености, може да се наблюдава странно пове-дение на програмата . Основната причина за този резултат е фактът, че при преобразуване към интерфейс структурите се опаковат и съответно се създава копие на данните, намиращи се в тях. Опаковането е съвсем в реда на нещата, като се има предвид, че структурите са стойностни типове, а интерфейсите са референтни типове.

57.Референтни типове.

Референтни типове (типове по референция) са указателите, класовете, интерфейсите, делегатите, масивите и опакованите стойностни типове. Физически референтните типове представляват указател към стойност в динамичната памет, но за CLR те не са обикновени указатели, а специ-ални типово-обезопасени указатели. Това означава, че CLR не допуска на един референтен тип да се присвои стойност от друг референтен тип, който не е съвместим с него (т.е. не е същия тип или негов наследник). В резултат на това в .NET езиците грешките от неправилна работа с типове са силно намалени.



Референтните типове и паметта

Всички референтни типове се съхраняват в динамичната памет (т. нар. managed heap), която се контролира от системата за почистване на паметта (garbage collector). Динамичната памет е специално място от паметта, заделено от CLR за съхранение на данни, които се създават динамично по време на изпълнението на програмата. Такива данни са инстанциите на всички референтни типове.

Когато инстанция на референтен тип престане да бъде необходима на програмата, тя се унищожава от системата за почистване на паметта (т. нар. garbage collector).

Когато инстанцираме референтен тип с оператора new, CLR заделя място в динамичната памет, където ще стоят данните и един указател в стека, който съдържа адреса на заделеното място. Веднага след това заделената памет се занулява (освен ако програмистът не инициализира заделената променлива, например чрез извикване на подходящ конструктор).

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

Референтните типове и производителността

Понякога се приема, че заделянето на динамична памет е бърза операция, защото в текущата реализация (.NET Framework 1.1) физически се импле-ментира чрез преместване на един указател. Освобождаването на памет, обаче, е сложна и времеотнемаща операция, която се извършва от време на време от системата за почистване на паметта (garbage collector).

Ако изчислим средното време, необходимо за заделяне и освобождаване на динамична памет, се оказва, че заделянето и освобождаван58.Интерфейсни типове. Използване на интерфейси със стойностни типове

Интерфейсът IComparable

Често пъти освен за равенство е необходимо обектите да се сравняват спрямо някаква подредба (например лексикографска за низове или по големина за числови типове). В .NET Framework типовете, които могат да бъдат сравнявани един с друг, трябва да имплементират интерфейса System.IComparable.

Интерфейсът дефинира един-единствен метод – CompareTo(object). Този метод трябва да реализира сравняването и да връща:

- число < 0 – ако подаденият обект е по-голям от this инстанцията

- 0 – ако подаденият обект е равен на this инстанцията

- число > 0 – ако подаденият обект е по-малък от this инстанцията


IComparable се използва от .NET Framework при сортиране на масиви и колекции и при някои други операции, изискващи сравнение по големина.

Системни имплементации на IComparable

IComparable е имплементиран от много системни .NET типове, като например от примитивните стойностни типове System.Char, System.Int32, System.Single, System.Double, от символните низове (System.String) и от изброените типове (System.Enum). Това улеснява разработчиците при всекидневната им работа и често пъти им спестява излишни усилия.

Интерфейсите IEnumerable и IEnumerator

В програмирането се срещат типове, които съдържат много на брой ин-станции на други типове. Такива типове се наричат контейнери или още колекции. Колекции например са масивите, защото съдържат много на брой еднакви елементи.

Често пъти се налага да се обходят всички елементи на даденa колекция. За да става това по стандартен начин, в .NET Framework са дефинирани интерфейсите IEnumerable и IEnumerator.

Интерфейсът IEnumerable

Интерфейсът System.IEnumerable се имплементира от колекции и други типове, които поддържат операцията "обхождане на елементите им в някакъв ред". Този интерфейс дефинира само един метод – методът GetEnumerator(). Той връща итератор (инстанция на IEnumerator) за обхождане на елементите на дадения обект.

Обектите, поддържащи IEnumerable интерфейса, могат да се използват от конструкцията foreach в C# за обхождане на всичките им елементи.

Интерфейсът IEnumerable е реализиран от много системни .NET типове, като System.Array, System.String, ArrayList, Hashtable, Stack, Queue, SortedList и др. с цел да се улесни работата с тях.



Интерфейсът IEnumerator

Интерфейсът System.IEnumerator имплементира обхождане на всички елементи на колекции и други типове. Той реализира прост итератор чрез следните методи и свойства:

- Свойство Current – връща текущия елемент.

- Метод bool MoveNext() – преминава към следващия елемент и връща true, ако той е валиден.

- Метод Reset() – премества итератора непосредствено преди първия елемент (установява го в начално състояние).

е на стой-ностните типове е значително по-бързо от референтните типове. Когато производителността е важна за нашата система, трябва да се съобразя-ваме с особеностите на стойностните и референтните типове и начина, по който те заделят и освобождават памет.

Глобално погледнато, нещата около управлението на динамичната памет в .NET Framework са доста комплексни, но в тази тема няма да се спираме на тях. По-нататък, в темата за управление на паметта и ресурсите, ще им обърнем специално внимание.

60.Делегати. Дефиниране, използване.

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

Делегатът се инстанцира като клас и методът се подава като параметър на конструктора. Възможно е делегатът да сочи към повече от един метод, но на това ще се спрем подробно малко по-нататък.

Съществува известна прилика между делегатите и указателите към функ-ции в други езици, например Pascal, C, C++, тъй като последните пред-ставляват типизиран указател към функция. Делегатите също съдържат силно типизиран указател към функция, но те са и нещо повече – те са напълно обектно-ориентирани. На практика делегатите представляват класове. Инстанцията на един делегат може да съдържа в себе си както инстанция на обект, така и метод.

Едно от основните приложения на делегатите е реализацията на "обратни извиквания", т.нар. callbacks. Идеята е да се предаде референция към метод, който да бъде извикан по-късно. Така може да се осъществи например асинхронна обработка – от даден код извикваме метод, като му подаваме callback метод и продължаваме работа, а извиканият метод извиква callback метода когато е необходимо. Със средствата на делега-тите е възможно даден клас да позволи на потребителите си да предос-тавят метод, извършващ специфична обработка, като по този начин обработката не се фиксира предварително.Делегатите в .NET Framework са специални класове, които наследяват System.Delegate или System.MulticastDelegate. От тези класове обаче явно могат да наследяват само CLR и компилаторът. Всъщност, те не са от тип делегат – тези класове се използват, за да се наследяват от тях типове делегат.

Всеки делегат има "списък на извикване" (invocation list), който представлява наредено множество делегати, като всеки елемент от него съдържа конкретен метод, рефериран от делегата. Делегатите могат да бъдат единични и множествени.
Единичните делегати наследяват класа System.Delegate. Тези делегати извикват точно един метод. В списъка си на извикване имат единствен елемент, съдържащ референция към метод.

ножествени (multicast) делегати

Множествените делегати наследяват класа System.MulticastDelegate, който от своя страна е наследник на класа на System.Delegate. Те могат да викат един или повече метода. Техните списъци на извикване съдър-жат множество елементи, всеки рефериращ метод. В тях може един и същ метод да се среща повече от веднъж. При извикване делегатът активира всички реферирани методи. Множествените делегати могат да участват в комбиниращи операции.

Езикът C# съдържа запазената дума delegate, чрез която се декларира делегат. При тази декларация компилаторът автоматично наследява типа MulticastDelegate., т.е. създава множествен делегат. Затова ще обърнем по-голямо внимание именно на този вид делегати.



19. LINQ – Language INtegrated Query. Query Expressions – Заявки вградени в езика. Ламбда изрази

LINQ – Language INtegrated Query 


( заявки вградени в езика )

  • Основни фундаменти на LINQ

  • LINQ - използвани езици C# 3.0 VB 9

  • Особености

    • Lambda Expressions

    • Query Expressions

      • Delegate functions

      • Type inference

      • Anonymous types

      • Extension methods

      • Expression trees

Инициализация на обекти

Invoice i = new Invoice { CustomerId = 123, Name = “Test” };



Is equivalent to:

Invoice I = new Invoice();

i.CustomerId = 123;

i.Name = “Test”;

Lambda Expressions
Predicates


    • Predicate

      • (p) => p.Gender == “F”
1   2   3   4




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

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