Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методичка для КР по ООП.doc
Скачиваний:
8
Добавлен:
18.04.2019
Размер:
2.47 Mб
Скачать

Атрибуты

Атрибут – средство добавления ДЕКЛАРАТИВНОЙ информации к элементам программного кода. Назначение атрибутов – внесение всевозможных не предусмотренных обычным ходом выполнения приложения изменений:

  • описание взаимодействия между модулями,

  • дополнительная информация, используемая при работе с данными (управление сериализацией),

  • отладка,

  • много чего другого.

Эта декларативная информация составляет часть метаданных кода. Она может быть использована при помощи механизмов отражения.

Структура атрибута регламентирована. Атрибут – это класс. Общий предок всех атрибутов – класс System.Attribute.

Информация, закодированная с использованием атрибутов, становится доступной в процессе ОТРАЖЕНИЯ (рефлексии типов).

Атрибуты типизированы.

.NET способна прочитать информацию в атрибутах и использовать её в соответствии с предопределёнными правилами или замыслами разработчика. Различаются

  • Предопределённые атрибуты. В .NET реализовано множество атрибутов с предопределёнными значениями:

DllImport – для загрузки .dll файлов.

Serializable – означает возможность сериализации свойств объекта-представителя класса.

NonSerialized – обозначает данные-члены класса как несериализуемые. Карандаши не сереализуются.

  • Производные (пользовательские) атрибуты могут определяться и использоваться в соответствии с замыслами разработчика. Возможно создание собственных (пользовательских) атрибутов. Главные условия:

соблюдение синтаксиса,

соблюдение принципа наследования.

В основе пользовательских атрибутов – всё та же система типов с наследованием от базового класса System.Attribute.

И не спроста! В конце-концов, информация, содержащаяся в атрибутах, предназначается для Framework.NET и она должна суметь в ней разбираться. Пользователи или другие инструментальные средства должны уметь кодировать и декодировать эту информацию.

Добавлять атрибуты можно к:

  • сборкам,

  • классам,

  • элементам класса,

  • структурам,

  • элементам структур,

  • параметрам,

  • возвращаемым значениям.

Следующий пример является демонстрацией объявление и применения производных атрибутов.

using System;

using System.Reflection;

namespace CustomAttrCS

{

// Перечисление of animals.

// Start at 1 (0 = uninitialized).

public enum Animal

{

// Pets.

Dog = 1,

Cat,

Bool,

}

// Перечисление of animals.

// Start at 1 (0 = uninitialized).

public enum Color

{

// Colors.

Red = 1,

Brown,

White,

}

// Класс пользовательских атрибутов.

public class AnimalTypeAttribute : Attribute

{//======================================================================

// Данное-член типа перечисление.

protected Animal thePet;

protected string WhoIs(Animal keyPet)

{

string retStr = “”;

switch (keyPet)

{

case Animal.Dog: retStr = “This is the Dog!”; break;

case Animal.Cat: retStr = “This is the Cat!”; break;

case Animal.Bool: retStr = “This is the Bool!”; break;

default: retStr = “Unknown animal!”; break;

}

return retStr;

}

// Конструктор вызывается при установке атрибута.

public AnimalTypeAttribute(Animal pet)

{

thePet = pet;

Console.WriteLine(«{0}», WhoIs(pet));

}

// Свойство, демонстрирующее значение атрибута.

public Animal Pet

{

get

{

return thePet;

}

set

{

thePet = Pet;

}

}

}//======================================================================

// Ещё один класс пользовательских атрибутов.

public class ColorTypeAttribute : Attribute

{//======================================================================

// Данное-член типа перечисление.

protected Color theColor;

// Конструктор вызывается при установке атрибута.

public ColorTypeAttribute(Color keyColor)

{

theColor = keyColor;

}

// Свойство, демонстрирующее значение атрибута.

public Color ColorIs

{

get

{

return theColor;

}

set

{

theColor = ColorIs;

}

}

}//======================================================================

// A test class where each method has its own pet.

class AnimalTypeTestClass

{//======================================================================

// Содержит объявления трёх методов, каждый из которых

// предваряется соответствующим ПОЛЬЗОВАТЕЛЬСКИМ атрибутом.

// У метода может быть не более одного атрибута данного типа.

[AnimalType(Animal.Dog)]

[ColorType(Color.Brown)]

public void DogMethod()

{

Console.WriteLine(“This is DogMethod()...”);

}

[AnimalType(Animal.Cat)]

public void CatMethod()

{

Console.WriteLine(“This is CatMethod()...”);

}

[AnimalType(Animal.Bool)]

[ColorType(Color.Red)]

public void BoolMethod(int n, string voice)

{

int i;

Console.WriteLine(“This is BoolMethod!”);

if (n > 0) for (i = 0; i < n; i++)

{

Console.WriteLine(voice);

}

}

}//======================================================================

class DemoClass

{//======================================================================

static void Main(string[] args)

{

int invokeFlag;

int i;

// И вот ради чего вся эта накрутка производилась...

// Объект класса AnimalTypeTestClass под именем testClass

// представляет собой КОЛЛЕКЦИЮ методов, каждый из которых

// снабжён соответствующим ранее определённым пользовательским

// СТАНДАРТНЫМ атрибутом. У класса атрибута AnimalTypeAttribute есть всё,

// что положено иметь классу, включая конструктор.

AnimalTypeTestClass testClass = new AnimalTypeTestClass();

// Так вот создали соответствующий объект-представитель класса...

// Объект-представитель класса сам может служить источником информации

// о собственном классе. Информация о классе представляется методом GetType()

// в виде объекта - представителя класса Type. Информационная капсула!

Type type = testClass.GetType();

// Из этой капсулы можно извлечь множество всякой «полезной» информации...

// Например, можно получить коллекцию (массив) элементов типа MethodInfo

// (описателей методов), содержащую список описателей методов, объявленных

// в данном классе. В список будет включена информация о ВСЕХ методах класса.

// О тех, которые были определены явным образом и те, которые были унаследованы

// от базовых классов. И по этому списку описателей методов мы пройдём

// победным маршем («Ha-Ha-Ha») оператором foreach.

i = 0;

foreach(MethodInfo mInfo

in

type.GetMethods())

{

invokeFlag = 0;

Console.WriteLine(“#####{0}#####{1}#####”, i, mInfo.Name);

// И у каждого из методов мы спросим относительно множества атрибутов,

// которыми метод был снабжён при объявлении класса.

foreach (Attribute attr

in

Attribute.GetCustomAttributes(mInfo))

{

Console.WriteLine(“~~~~~~~~~~”);

// Check for the AnimalType attribute.

if (attr.GetType() == typeof(AnimalTypeAttribute))

{

Console.WriteLine(“Method {0} has a pet {1} attribute.”,

mInfo.Name,

((AnimalTypeAttribute)attr).Pet);

// Посмотрели значение атрибута - и если это Animal.Bool - подняли флажок.

if (((AnimalTypeAttribute)attr).Pet.CompareTo(Animal.Bool) == 0) invokeFlag++;

}

if (attr.GetType() == typeof(ColorTypeAttribute))

{

Console.WriteLine(“Method {0} has a color {1} attribute.”,

mInfo.Name,

((ColorTypeAttribute)attr).ColorIs);

// Посмотрели значение атрибута - и если это Animal.Bool - подняли флажок.

if (((ColorTypeAttribute)attr).ColorIs.CompareTo(Color.Red) == 0) invokeFlag++;

}

// И если случилось счастливое совпадение значений атрибутов метода,

// метод выполняется.

// Метод Invoke в варианте с двумя параметрами:

// объект-представитель исследуемого класса

// (в данном случае AnimalTypeTestClass), и массив объектов - параметров.

if (invokeFlag == 2)

{

object[] param = {5,”Mmmuuu-uu-uu!!! Mmm...”};

mInfo.Invoke(new AnimalTypeTestClass(),param);

}

Console.WriteLine(“~~~~~~~~~~”);

}

Console.WriteLine(“#####{0}#####”, i);

i++;

}

}

}//======================================================================

}