-
Обяснете какво представляват делегатите в .NET Framework.
-
Обяснете какво представляват събитията (events) в .NET Framework.
-
Какво се препоръчва от утвърдената конвенция за събитията в .NET Framework? Опишете програмния код за дефиниране и използване на събития.
-
Чрез средствата на делегатите реализирайте универсален статичен метод за изчисляване с някаква точност на безкрайни сходящи редове по зададена функция за общия им член. Чрез подходящи функции за общия член изчислете с точност два десетични знака безкрайните редове:
-
1 + 1/2 + 1/4 + 1/8 + 1/16 + …
-
1 + 1/4 + 1/9 + 1/16 + 1/25 + …
-
1 + 1/2! + 1/3! + 1/4! + 1/5! + …
-
Напишете клас Person, който описва един човек и съдържа свойствата: име, презиме, фамилия, пол, рождена дата, ЕГН, адрес, e-mail и телефон. Добавете към класа Person за всяко от неговите свойства по едно събитие от системния делегат System.EventHandler, което се активира при промяна на съответното свойство.
-
Създайте клас PropertyChangedEventArgs, наследник на класа System.EventArgs и дефинирайте в него три свойства – име на променено свойство (string), стара стойност (object) и нова стойност (object) заедно с подходящ конструктор. Създайте делегат PropertyChangedEventHandler за обработка на събития, който да приема два параметъра – обект-изпращач и инстанция на PropertyChangedEventArgs.
-
Напишете нов вариант на класа Person, който има само едно събитие с име PropertyChanged от тип PropertyChangedEventHandler, което се активира при промяна на някое от свойствата на класа (и съответно се извиква с подходящи параметри).
-
Изнесете дефиницията на събитието PropertyChanged в отделен интерфейс и променете класа така, че да имплементира интерфейса.
-
Светлин Наков, Делегати и събития – http://www.nakov.com/dotnet/ lectures/Lecture-5-Delegates-and-Events-v1.0.ppt
-
Jeffrey Richter, Applied Microsoft .NET Framework Programming, Microsoft Press, 2002, ISBN 0735614229
-
Jesse Liberty, Programming C#, O’Reilly, 2001, ISBN 0-596-00117-7
-
Andrew Whitechapel, Tom Archer, Inside C#, Microsoft Press, 2002, ISBN 0-7356-1648-5
-
MSDN Training, Programming with the Microsoft® .NET Framework (MOC 2349B), Module 8: Delegates and Events
-
Julien Couvreur, Curiosity is bliss – http://blog.monstuff.com/archives/ 000040.html
-
MSDN Library – http://msdn.microsoft.com
Глава 7. Атрибути Необходими знания -
Базови познания за архитектурата на .NET Framework
-
Базови познания за общата система от типове в .NET (Common Type System)
-
Базови познания за езика C#
Съдържание -
Какво представляват атрибутите?
-
Прилагане на атрибути. Атрибути с параметри. Задаване на цел при прилагане на атрибут
-
Къде се използват атрибутите?
-
Дефиниране на собствени атрибути
-
Извличане на атрибути от метаданните
-
Мета-атрибутът AttributeUsage
В тази тема ...
В настоящата тема ще разгледаме какво представляват атрибутите в .NET Framework, как се прилагат и къде се използват. Ще обясним как могат да се дефинират собствени атрибути и да се извличат атрибути от метаданните на асемблитата.
Какво представляват атрибутите в .NET?
В повечето езици за програмиране съществуват ключови думи. Такива например са спецификаторите за достъп, които определят областта на видимост на член-променливите на класовете (public, private, protected, …). Най-често компилаторите разпознават само ограничен набор ключови думи и програмистите нямат възможност да дефинират свои собствени.
За компенсиране на тази слабост в .NET Framework се дава възможност програмно да се добавят т. нар. атрибути. Те представляват описателни декларации към типове, полета, методи, свойства и други елементи на кода, подобни на ключовите думи от езиците за програмиране.
Атрибутите позволяват да се добавят собствени описателни елементи (анотации) към кода, написан на C# или на някой от другите езици от .NET платформата, без да се налага промяна в компилатора. По време на компилация те се записват в метаданните на асемблито и при изпълнение на кода могат да бъдат извличани и да влияят на поведението му.
Атрибутите са описателни тагове, които могат да се прилагат към различни елементи от кода, наричани цели. Целите могат да бъдат най-разнообразни: асемблита, типове, свойства, полета, методи, параметри и други елементи от кода.
Декларативна информация се асоциира с програмния код (към типовете, методите, свойствата и т.н.) чрез атрибути. Други приложения могат да извличат тази информация, за да определят как да бъдат използвани елементите, свързани с атрибутите.
Атрибутите реално представляват класове, които се инстанцират по време на компилация на сорс кода и се записват в метаданните на асемблито, от където могат да бъдат извличани по време на работа на приложението.
Атрибутите се делят на две групи – вградени в .NET Framework (които са част от CLR) и дефинирани от програмистите за целите на отделните приложения. Последните се наричат собствени (потребителски) атрибути и най-често се използват в комбинация с reflection (отражение на типовете).
По-долу ще разгледаме начините, по които можем да приложим атрибут към дадена цел.
За да се приложи атрибут, името му се огражда в квадратни скоби и се поставя непосредствено преди декларацията, за която се отнася. Ето един пример:
// Apply attribute System.FlagsAttribute to FileAccess enum
[Flags]
public enum FileAccess
{
Read = 1,
Write = 2,
ReadWrite = Read | Write
}
|
В посочения пример системният атрибут Flags (реално това е типът System.FlagsAttribute) е приложен към дефиницията на изброения тип FileAccess и указва, че този изброен тип може да се третира като битово поле, т.е. като множество от битови флагове.
За да бъде приложен атрибут към дадена дефиниция в кода, трябва да се изпълнят следните стъпки:
-
Да се дефинира нов атрибут или да се използва съществуващ, като неговото пространство от имена (namespace) се импортира в началото на текущия файл от сорс кода.
-
Да се изпише името на атрибута в квадратни скоби точно преди целта, към която се прилага. По желание могат да му бъдат предадени някакви параметри (инициализиращи данни).
Атрибутите за дадена цел могат да се прилагат и в комбинация. Това става по два начина: като се приложат един след друг или като се изброят със запетаи:
[MyFirstAttribute]
[MySecondAttribute]
public void SomeMethod() { … }
[MyFirstAttribute, MySecondAttribute]
public void SomeMethod() { … }
|
Двете декларации в горния пример са напълно еквивалентни. Те дефинират публичен метод SomeMethod() и прилагат към него атрибутите MyFirstAttribute и MySecondAttribute.
При прилагането на атрибути суфиксът Attribute може да бъде пропуснат и се подразбира от компилатора. Така следните декларации са еквивалентни на горните две:
[MyFirst]
[MySecond]
public void SomeMethod() { … }
[MyFirst, MySecond]
public void SomeMethod() { … }
|
Тъй като атрибутите са класове, при тяхното прилагане може да бъде извикван конструкторът на съответния клас. Ако атрибутът предлага конструктор без параметри, той може да бъде извикан като се добави () към декларацията. Следователно следващите две декларации са валидни и еквивалентни на предходните две:
[MyFirst()]
[MySecondAttribute()]
public void SomeMethod() { … }
[MyFirstAttribute(), MySecond()]
public void SomeMethod() { … }
|
От примерите виждаме, че има много синтактично валидни начини за прилагане на един и същ атрибут към дадена цел. За компилатора няма значение кой от тези варианти е употребен, но препоръката е да се използва този без суфикс Attribute, без изброяване със запетаи и без скоби (). За нашия пример препоръчителен е следният запис:
[MyFirst]
[MySecond]
public void SomeMethod() { … }
| Атрибутите са обекти
Атрибутите в .NET Framework реално представляват .NET обекти (инстанции на клас, наследник на системния клас System.Attribute). Като такива те могат да имат един или няколко конструктора (вкл. конструктор по подразбиране), публични и частни полета, свойства и др. членове. Най-често атрибутите дефинират конструктори, публични полета и свойства, които използват за съхраняване на данните, подавани им като параметри по време на инициализация.
Всички атрибути в .NET Framework задължително наследяват класа System.Attribute (или негов наследник). Както ще видим по-долу, при дефиниране на собствени (потребителски атрибути) ние също трябва да наследяваме този клас.
Параметри на атрибутите
Някои атрибути могат да приемат параметри. Параметрите биват два вида: позиционни и именувани. Позиционните параметри се подават с определена последователност и се инициализират от конструктора на атрибута, докато именуваните се подават в произволен ред и задават стойност на свойство или публично поле. Ето един пример:
[DllImport("user32.dll", EntryPoint="MessageBox")]
public static extern int ShowMessageBox(int hWnd, string text,
string caption, int type);
...
ShowMessageBox(0, "Some text", "Some caption", 0);
|
В примера е използвана комбинация между позиционни и непозиционни параметри. За да бъде приложен към метаданните в асемблито, атрибутът [DllImport] (System.Runtime.InteropServices.DllImportAttribute) по време на компилация се инстанцира и инициализира от компилатора по следния начин:
-
Създава се обект от класа System.Runtime.InteropServices. DllImportAttribute.
-
В конструктора му се подава като позиционен параметър стойност "user32.dll".
-
В публичното му поле EntryPoint се записва стойност "MessageBox".
Преди да бъдат записани в метаданните на съответното асембли, атрибутите се инициализират посредством подадените им параметри, с които се задават стойности за техните полета и свойства. При съхраняване в асемблито атрибутите запазват състоянието си.
На по-късен етап, когато атрибутите бъдат извлечени от метаданните на асемблито, стойностите на техните полета и свойства се извличат заедно с тях и могат да бъдат използвани от програмиста.
Задаване на цел към атрибут
Атрибутите в .NET Framework могат да се прилагат към различни цели, например асембли, клас, интерфейс, член-променлива на тип и др. Възможните цели на атрибутите се дефинират от изброения тип AttributeTargets както следва:
Име на целта
|
Употреба (прилага се към)
|
Assembly
|
самото асембли
|
Module
|
текущия модул
|
Class
|
клас
|
Struct
|
структура
|
Interface
|
интерфейс
|
Enum
|
изброен тип
|
Delegate
|
делегат
|
Constructor
|
конструктор
|
Method
|
метод
|
Parameter
|
параметър на метод
|
ReturnValue
|
връщаната стойност от метод
|
Property
|
свойство
|
Field
|
поле (член-променлива)
|
Event
|
събитие
|
All
|
всички възможни цели
|
При прилагане на атрибут целта обикновено се подразбира. Например, ако поставим атрибут преди декларацията на даден метод, той ще се отнася за съответния метод.
Понякога не може да се използва целта по подразбиране, например ако искаме да приложим атрибут към асемблито. В такива случаи целта може да се зададе преди името на атрибута, отделена от него с двоеточие:
// The following attributes are applied to the target "assembly"
[assembly: AssemblyTitle("Attributes Demo")]
[assembly: AssemblyCompany("DemoSoft")]
[assembly: AssemblyProduct("Entreprise Demo Suite")]
[assembly: AssemblyCopyright("(c) 1963-1964 DemoSoft")]
[assembly: AssemblyVersion("2.0.1.37")]
[Serializable] // The compiler assumes [type: Serializable]
class TestClass
{
[NonSerialized] // The compiler assumes [field: NonSerialized]
private int mStatus;
...
}
|
Както се вижда от коментарите в кода, за някои от атрибутите целта се задава експлицитно, а за други тя се подразбира.
Сподели с приятели: |