Перейти к содержимому

Что такое атрибут в программировании

  • автор:

Атрибутивное программирование. Часто задаваемые вопросы

HRESULT — это простой тип данных, который часто используется в качестве возвращаемого значения атрибутами и ATL в целом. В следующей таблице описаны различные значения. Дополнительные значения содержатся в файле заголовка winerror.h.

Имя Описание Значение
S_OK Операция выполнена успешно 0x00000000
E_UNEXPECTED Непредвиденный сбой 0x8000FFFF
E_NOTIMPL Не реализовано 0x80004001
E_OUTOFMEMORY Не удалось выделить необходимую память 0x8007000E
E_INVALIDARG Один или несколько аргументов недопустимы 0x80070057
E_NOINTERFACE Такой интерфейс не поддерживается 0x80004002
E_POINTER Недопустимый указатель 0x80004003
E_HANDLE Недопустимый дескриптор 0x80070006
E_ABORT Операция прервана 0x80004004
E_FAIL Неуказанный сбой 0x80004005
E_ACCESSDENIED Общая ошибка отказа в доступе 0x80070005

Когда нужно указать имя параметра для атрибута?

В большинстве случаев, если атрибут имеет один параметр, этот параметр называется. Это имя не требуется при вставке атрибута в код. Например, следующее использование агрегируемого атрибута:

[coclass, aggregatable(value=allowed)] class CMyClass < // The class declaration >; 

точно так же, как:

[coclass, aggregatable(allowed)] class CMyClass < // The class declaration >; 

Однако следующие атрибуты имеют одинарные неименованные параметры:

Можно ли использовать комментарии в блоке атрибутов?

В блоке атрибутов можно использовать как однострочные, так и несколько строковый комментарий. Однако нельзя использовать любой стиль комментариев в скобках, где параметры заданы атрибуту.

[ coclass, progid("MyClass.CMyClass.1"), /* Multiple-line comment */ threading("both") // Single-line comment ] 
[ coclass, progid("MyClass.CMyClass.1" /* Multiple-line comment */ ), threading("both" // Single-line comment) ] 

Как атрибуты взаимодействуют с наследованием?

Можно наследовать как атрибуты, так и неуправляемые классы от других классов, которые могут быть атрибутами или нет. Результатом производных от класса атрибутов является то же самое, что и производный от этого класса после преобразования своего кода поставщиком атрибутов. Атрибуты не передаются производным классам через наследование C++. Поставщик атрибутов преобразует код только в непосредственной близости от его атрибутов.

Как использовать атрибуты в неатрибуционном проекте ATL?

Возможно, у вас есть неатрибуционный проект ATL, имеющий IDL-файл, и вы можете начать добавлять объекты с атрибутами. В этом случае используйте мастер добавления классов для предоставления кода.

Как использовать IDL-файл в проекте с атрибутами?

У вас может быть IDL-файл, который вы хотите использовать в проекте атрибутов ATL. В этом случае вы будете использовать атрибут importidl, скомпилируйте IDL-файл в H-файл (см. страницы свойств MIDL в диалоговом окне страниц свойств проекта), а затем включите H-файл в проект.

Можно ли изменить код, который внедряется атрибутом?

Некоторые атрибуты внедряют код в проект. Вы можете просмотреть внедренный код с помощью параметра компилятора /Fx . Также можно скопировать код из внедренного файла и вставить его в исходный код. Это позволяет изменить поведение атрибута. Однако может потребоваться изменить другие части кода.

Следующий пример является результатом копирования внедренного кода в файл исходного кода:

// attr_injected.cpp // compile with: comsupp.lib #define _ATL_ATTRIBUTES 1 #include #include [ module(name="MyLibrary") ]; // ITestTest [ object, uuid("DADECE00-0FD2-46F1-BFD3-6A0579CA1BC4"), dual, helpstring("ITestTest Interface"), pointer_default(unique) ] __interface ITestTest : IDispatch < [id(1), helpstring("method DoTest")] HRESULT DoTest([in] BSTR str); >; // _ITestTestEvents [ uuid("12753B9F-DEF4-49b0-9D52-A79C371F2909"), dispinterface, helpstring("_ITestTestEvents Interface") ] __interface _ITestTestEvents < [id(1), helpstring("method BeforeChange")] HRESULT BeforeChange([in] BSTR str, [in,out] VARIANT_BOOL* bCancel); >; // CTestTest [ coclass, threading(apartment), vi_progid("TestATL1.TestTest"), progid("TestATL1.TestTest.1"), version(1.0), uuid("D9632007-14FA-4679-9E1C-28C9A949E784"), // this line would be commented out from original file // event_source("com"), // this line would be added to support injected code source(_ITestTestEvents), helpstring("TestTest Class") ] class ATL_NO_VTABLE CTestTest : public ITestTest, // the following base classes support added injected code public IConnectionPointContainerImpl, public IConnectionPointImpl  < public: CTestTest() < >// this line would be commented out from original file // __event __interface _ITestTestEvents; DECLARE_PROTECT_FINAL_CONSTRUCT() HRESULT FinalConstruct() < return S_OK; >void FinalRelease() <> public: CComBSTR m_value; STDMETHOD(DoTest)(BSTR str) < VARIANT_BOOL bCancel = FALSE; BeforeChange(str,&bCancel); if (bCancel) < return Error("Error : Someone don't want us to change the value"); >m_value =str; return S_OK; > // the following was copied in from the injected code. HRESULT BeforeChange(::BSTR i1. VARIANT_BOOL* i2) < HRESULT hr = S_OK; IConnectionPointImpl* p = this; VARIANT rgvars[2]; Lock(); IUnknown** pp = p->m_vec.begin(); Unlock(); while (pp < p->m_vec.end()) < if (*pp != NULL) < IDispatch* pDispatch = (IDispatch*) *pp; ::VariantInit(&rgvars[1]); rgvars[1].vt = VT_BSTR; V_BSTR(&rgvars[1])= (BSTR) i1; ::VariantInit(&rgvars[0]); rgvars[0].vt = (VT_BOOL | VT_BYREF); V_BOOLREF(&rgvars[0])= (VARIANT_BOOL*) i2; DISPPARAMS disp = < rgvars, NULL, 2, 0 >; VARIANT ret_val; hr = __ComInvokeEventHandler(pDispatch, 1, 1, &disp, &ret_val); if (FAILED(hr)) break; > pp++; > return hr; > BEGIN_CONNECTION_POINT_MAP(CTestTest) CONNECTION_POINT_ENTRY(__uuidof(::_ITestTestEvents)) END_CONNECTION_POINT_MAP() // end added code section // _ITestCtrlEvents Methods public: >; int main() <> 

Как перенаправить объявление интерфейса атрибута?

Если вы собираетесь сделать перенаправленное объявление интерфейса с атрибутами, необходимо применить те же атрибуты к объявлению пересылки, которое применяется к фактическому объявлению интерфейса. Кроме того, необходимо применить атрибут экспорта к объявлению пересылки.

Можно ли использовать атрибуты для класса, производного от класса, который также использует атрибуты?

Нет, использование атрибутов в классе, производном от класса, который также использует атрибуты, не поддерживается.

Атрибуты в C#

Достаточно много времени до меня не доходило что же за такая штука эти Атрибуты.

Сел, разобрался, прочитал непонятные определения и предлагаю полученное мной понимание о том что же это такое.

Атрибут — это класс, унаследованный от базового класса Attribute.
Суть атрибута в том, что он используется для генерации описаний. Создав атрибут вы можете наделить его своими свойствами которыми вы желаете наградить класс, поле, свойство или метод, Атрибут не влияет на значение полей и свойств и на выполнение методов класса, если в теле метода не учитывается информация хранящаяся в атрибуте. Но есть очень важный момент — Значение атрибута невозможно изменять в процессе выполнения кода, так как значения их свойств хранятся в виде констант в скомпилированном модуле

Например с помощью атрибутов вы можете проанализировав их значения для типа построить различные схемы выполнения действий над ним.
Не очень понятно, тогда пример:

public class MyAttribute : Attribute // создаём собственный атрибут наследуясь от стандартного класса < public int Count < get; set; >// создаём своё свойство которое будет содержать атрибут // можно описать несколько свойств но для примера создаётся только одно > 

И некий класс который мы наградим описанным атрибутом и будем использовать его значение для формирования результата функции GetArray:

[MyAttribute< Count = 3 >] public class IntArrayInitializer < public int[] GetArray() < var type = this.GetType(); // получение описания типа if (Attribute.IsDefined(type, typeof(MyAttribute))) // проверка на существование атрибута < var attributeValue = Attribute.GetCustomAttribute(type, typeof(MyAttribute)) as MyAttribute; // получаем значение атрибута return new int[attributeValue.Count]; // используем значение атрибута для формирования результата >return new int[0]; > > 

Как видно из кода, сначала мы получаем описание нашего класса, далее проверяем наличие нашего атрибута и в случае его наличия мы формируем массив с указанным в атрибуте количеством элементов.

А теперь унаследовавшись от этого класса и задав новому классу другое значение атрибута при вызове метода мы получим массив нужной размерности.

Данная статья даёт только общее и скудное описание атрибутов, но используя его, можно понять, что это такое.

Как работать с атрибутами классов и экземпляров в Python

Изучите атрибуты классов и экземпляров в Python, чтобы стать мастером объектно-ориентированного программирования!

Алексей Кодов
Автор статьи
10 июля 2023 в 17:48

Атрибуты классов и экземпляров являются важной частью объектно-ориентированного программирования (ООП) в Python. В этой статье мы разберем, как использовать и работать с атрибутами классов и экземпляров.

Атрибуты классов

Атрибуты классов определяются внутри класса и являются общими для всех объектов этого класса. Они могут быть использованы для хранения констант или общих настроек.

class MyClass: attribute = "value" print(MyClass.attribute) # Вывод: "value"

Атрибуты экземпляров

Атрибуты экземпляра определяются для каждого объекта класса и обычно используются для хранения состояния объекта. Они определяются внутри метода __init__ .

class MyClass: def __init__(self): self.attribute = "value" obj = MyClass() print(obj.attribute) # Вывод: "value"

Работа с атрибутами

Для доступа к атрибутам класса или экземпляра используйте точечную нотацию:

class MyClass: class_attribute = "class value" def __init__(self): self.instance_attribute = "instance value" obj = MyClass() print(MyClass.class_attribute) # Вывод: "class value" print(obj.instance_attribute) # Вывод: "instance value"

Python-разработчик: новая работа через 9 месяцев
Получится, даже если у вас нет опыта в IT

Если вам нужно изменить значение атрибута, просто присвойте ему новое значение:

class MyClass: class_attribute = "class value" def __init__(self): self.instance_attribute = "instance value" obj = MyClass() obj.instance_attribute = "new instance value" MyClass.class_attribute = "new class value" print(MyClass.class_attribute) # Вывод: "new class value" print(obj.instance_attribute) # Вывод: "new instance value"

�� Однако изменять атрибуты класса через экземпляр класса может привести к неочевидным результатам:

class MyClass: class_attribute = "class value" def __init__(self): self.instance_attribute = "instance value" obj1 = MyClass() obj2 = MyClass() obj1.class_attribute = "new class value" print(MyClass.class_attribute) # Вывод: "class value" print(obj1.class_attribute) # Вывод: "new class value" print(obj2.class_attribute) # Вывод: "class value"

Здесь изменение class_attribute через экземпляр obj1 создало новый атрибут экземпляра с тем же именем, вместо изменения атрибута класса.

Вывод

В этой статье мы рассмотрели основы работы с атрибутами классов и экземпляров в Python. Эти принципы помогут вам понять и использовать ООП в Python для создания структурированных и модульных программ. Удачи в изучении Python! ��

Что такое атрибут в программировании

Атрибуты в .NET представляют специальные инструменты, которые позволяют встраивать в сборку дополнительные метаданные. Атрибуты могут применяться как ко всему типу (классу, интерфейсу и т.д.), так и к отдельным его частям (методу, свойству и т.д.). Основу атрибутов составляет класс System.Attribute , от которого образованы все остальные классы атрибутов. В .NET имеется множество встроенных классов атрибутов. И также мы можем создавать свои собственные классы атрибутов, которые будут определять метаданные других типов.

Допустим, нам надо проверять пользователя на соответствие некоторым возрастным ограничениям. Создадим свой атрибут, который будет хранить пороговое значение возраста, с которого разрешены некоторые действия:

class AgeValidationAttribute : Attribute < public int Age < get;>public AgeValidationAttribute() < >public AgeValidationAttribute(int age) => Age = age; >

По сути это обычный класс, унаследованный от System.Atribute. В нем определено два конструктора: с параметром и без. В качестве параметра второй конструктор атрибута принимает некий пороговый возраст и сохраняет его в свойстве.

Теперь применим его к некоторому классу:

[AgeValidation(18)] public class Person < public string Name < get;>public int Age < get; set; >public Person(string name, int age) < Name = name; Age = age; >>

Данный класс Person применяет атрибут. Для этого имя атрибута указывается в квадратных скобках непосредственно перед определением класса. Причем суффикс Attribute указывать необязательно. Обе записи [AgeValidation(18)] и [AgeValidationAttribute(18)] будут равноправны.

Если конструктор атрибута предусматривает использование параметров ( public AgeValidationAttribute(int age) ), то после имени атрибута мы можем указать значения для параметров конструктора. В данном случае передается значение для параметра age . То есть фактически мы говорим, что в AgeValidationAttribute свойство Age будет иметь значение 18.

В качестве альтернативы можно использовать именованные параметры для всех свойств атрибута, если класс атрибута имеет конструктор без параметров: [AgeValidation(Age = 18)]

Теперь получим атрибут класса Person и используем его для проверки объектов данного класса:

Person tom = new Person("Tom", 35); Person bob = new Person("Bob", 16); bool tomIsValid = ValidateUser(tom); // true bool bobIsValid = ValidateUser(bob); // false Console.WriteLine($"Результат валидации Тома: "); Console.WriteLine($"Результат валидации Боба: "); bool ValidateUser(Person person) < Type type = typeof(Person); // получаем все атрибуты класса Person object[] attributes = type.GetCustomAttributes(false); // проходим по всем атрибутам foreach (Attribute attr in attributes) < // если атрибут представляет тип AgeValidationAttribute if (attr is AgeValidationAttribute ageAttribute) // возвращаем результат проверки по возрасту return person.Age >= ageAttribute.Age; > return true; > class AgeValidationAttribute : Attribute < public int Age < get;>public AgeValidationAttribute() < >public AgeValidationAttribute(int age) => Age = age; > [AgeValidation(18)] public class Person < public string Name < get;>public int Age < get; set; >public Person(string name, int age) < Name = name; Age = age; >>

В данном случае в методе ValidateUser через параметр получаем некоторый объект Person и с помощью метода GetCustomAttributes вытаскиваем из типа Person все атрибуты. Далее берем из атрибутов атрибут AgeValidationAttribute при его наличии (ведь мы можем его и не применять к классу) и проверям допустимость возраста пользователя. Если пользователь прошел проверку по возрасту, то возвращаем true, иначе возвращаем false. Если атрибут не применяется, возвращаем true.

Ограничение применения атрибута

С помощью атрибута AttributeUsage можно ограничить типы, к которым будет применяться атрибут. Например, мы хотим, чтобы выше определенный атрибут мог применяться только к классам:

[AttributeUsage(AttributeTargets.Class)] class AgeValidationAttribute : Attribute < //. >

Ограничение задает перечисление AttributeTargets , которое может принимать еще ряд значений:

  • All : используется всеми типами
  • Assembly : атрибут применяется к сборке
  • Constructor : атрибут применяется к конструктору
  • Delegate : атрибут применяется к делегату
  • Enum : применяется к перечислению
  • Event : атрибут применяется к событию
  • Field : применяется к полю типа
  • Interface : атрибут применяется к интерфейсу
  • Method : применяется к методу
  • Property : применяется к свойству
  • Struct : применяется к структуре

С помощью логической операции ИЛИ можно комбинировать эти значения. Например, пусть атрибут может применяться к классам и структурам: [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *