Перфолента.NET. ООП. Как написать свой атрибут — различия между версиями

Материал из ТХАБ.РФ
Перейти к: навигация, поиск
м
м (= Пример с фиксированным значением атрибута)
 
(не показано 9 промежуточных версий этого же участника)
Строка 1: Строка 1:
 
== Устройство атрибута ==
 
== Устройство атрибута ==
  
Технически, атрибуты — это специальные классы, унаследованные от класса Атрибут, который в .Net соответствует классу System.Attribute.
+
Технически, атрибуты — это специальные классы, унаследованные от [[класса Атрибут]], который в .Net соответствует классу [[System.Attribute]].
 +
 
 
Атрибуты могут что-то значить сами по себе или иметь конструктор, принимающий на хранение дополнительную информацию в виде параметров.  Типы параметров конструктора атрибута, а также полей и свойств, ограничены в .Net следующими типами:  
 
Атрибуты могут что-то значить сами по себе или иметь конструктор, принимающий на хранение дополнительную информацию в виде параметров.  Типы параметров конструктора атрибута, а также полей и свойств, ограничены в .Net следующими типами:  
 
Цел8, Цел32, Цел64, Байт, Бит32, Бит64, Вещ, ДВещ, Строка, Символ, Булево, Тип,
 
Цел8, Цел32, Цел64, Байт, Бит32, Бит64, Вещ, ДВещ, Строка, Символ, Булево, Тип,
Строка 7: Строка 8:
  
 
К сожалению, платформа .Net не поддерживает тип Дата в качестве параметра атрибута, но при необходимости дату (как и другие сериализуемые типы) можно представлять строкой.
 
К сожалению, платформа .Net не поддерживает тип Дата в качестве параметра атрибута, но при необходимости дату (как и другие сериализуемые типы) можно представлять строкой.
 +
 
== Написание собственного атрибута и его использование ==
 
== Написание собственного атрибута и его использование ==
  
У атрибута нет логики, он просто хранит несколько параметров, что бы их можно было прочитать в будущем.
+
У атрибута нет логики (т.е. нет методов), он просто хранит несколько параметров, что бы их можно было прочитать в будущем.
 +
 
 +
=== Пример Атрибута ===
 +
Определим простейший атрибут '''ЕдиницаИзмерений''', которым будем помечать физический тип и размерность значений у переменных (например: км/час, кГ, грамм, литр):
 +
 
 +
&ВидноВсем // Классу ЕденицаИзмерений присваивается атрибут &ВидноВсем
 +
Класс ЕденицаИзмерений Родитель Атрибут
 +
        Поле _ЕдИзмерений тип Строка // Каждый экземпляр этого класса будет иметь одно поле типа Строка в котором будет указанна единица измерений
 +
        &ВидноВсем
 +
        Конструктор(Синоним тип Строка)
 +
                _ЕдИзмерений = ЕдИзмерений
 +
        КонецКонструктора
 +
        &ВидноВсем
 +
        Функция ПолучитьЕдиницаИзмерений() тип Строка
 +
                Возврат _ЕдИзмерений
 +
        КонецФункции
 +
КонецКласса
 +
 
 +
Присваивание атрибута '''ЕдиницаИзмереинй''' - Полю '''Скорость'''.
 +
 
 +
&ЕденицаИзмерений ("км/час"), ВидноВсем // Полю Скорость присвоен атрибут ВидноВсем
 +
// и атрибут ЕденицаИзмерений значение которого равно "км/час"
 +
Поле Скорость тип Целое = 55 
 +
 
 +
Т.о. проверив атрибут Поля '''Скорость''', мы получим "км/час"
 +
 
 +
ЕдиницаИзмеренийСкорости = Скорость.ПолучитьЕдиницаИзмерений()
 +
 
 +
Строковое поле ЕдиницаИзмеренийСкорости будет равно "км/час"
 +
 
 +
=== Пример с фиксированным  значением атрибута ===
 +
 
 +
&ВидноВсем // Классу атрибута Рубль присваивается атрибут &ВидноВсем и фиксированное значение "Рубль"
 +
Класс Рубль Родитель Атрибут
 +
        Поле _ЕдницаРасчёта тип Строка // Каждый экземпляр этого класса будет иметь одно поле типа Строка в котором будет указанна единица расчёта
 +
        &ВидноВсем
 +
        Конструктор(Синоним тип Строка)
 +
                _ЕдиницаРасчёта = "Рубль"
 +
        КонецКонструктора
 +
        &ВидноВсем
 +
        Функция ПолучитьЕдиницаРасчёта() тип Строка
 +
                Возврат _ЕдиницаРасчёта
 +
        КонецФункции
 +
КонецКласса
 +
 
 +
Присваивание атрибута '''Рубль''' - Полю '''Цена'''.
 +
 
 +
&Рубль, ВидноВсем // Полю Цена присвоен атрибут ВидноВсем и Рубль
 +
  Поле Цена тип Вещ = 55,7  // Т.е. полю цена при военно вещественное значение 55,7 с атрибутом "Рубль" обозначающим что цена в рублях ,а не копейках или Евро.
 +
 
 +
Т.о. проверив атрибут Поля '''Скорость''', мы получим "км/час"
 +
 
 +
ЕденицаРасчётыЦены = Цена.ПолучитьЕдиницаРасчёта
 +
 
 +
Строковое поле ЕденицаРасчётыЦены будет равно "Рубль" проверив его перед операцией мы ошибочно не прибавим к 10 рублям 25 копеек или 16 Евро
 +
 
 +
=== *** ===
  
 
Например, Атрибут - '''АнглийскийСиноним''' может использоваться компилятором, если пользователь вдруг решил писать код на английском языке, тогда компилятор будет искать метод не только по именам, но и по синонимам.
 
Например, Атрибут - '''АнглийскийСиноним''' может использоваться компилятором, если пользователь вдруг решил писать код на английском языке, тогда компилятор будет искать метод не только по именам, но и по синонимам.
Строка 26: Строка 84:
 
Определим простейший атрибут '''АнглийскийСиноним''':
 
Определим простейший атрибут '''АнглийскийСиноним''':
  
  &ВидноВсем
+
  &ВидноВсем // Классу АнглийскийСиноним пристраивается атрибут &ВидноВсем
 
  Класс АнглийскийСиноним Родитель Атрибут
 
  Класс АнглийскийСиноним Родитель Атрибут
         Поле _Синоним тип Строка
+
         Поле _Синоним тип Строка // Каждый экземпляр этого класса будет иметь одно поле типа Строка  
 
         &ВидноВсем
 
         &ВидноВсем
 
         Конструктор(Синоним тип Строка)
 
         Конструктор(Синоним тип Строка)
Строка 39: Строка 97:
 
  КонецКласса
 
  КонецКласса
  
Как видим, кроме наследования от типа Атрибут, других особенностей у класса-атрибута нет.
+
Как видим, кроме наследования от типа Атрибут, других особенностей у класса-атрибута нет. Т.к. объект типа Атрибут - создаётся от обычного класса то ему самому можно присваивать атрибуты. В данном случае всем объектам типа АнглийскийСиноним будет присвоен атрибут &ВидноВсем.
  
 
Используем созданный нами атрибут АнглийскийСиноним для одного из методов программы - Процедуры Старт:
 
Используем созданный нами атрибут АнглийскийСиноним для одного из методов программы - Процедуры Старт:
Строка 45: Строка 103:
 
  &АнглийскийСиноним("Start"), ВидноВсем // Процедуре Страт присвоен атрибут ВидноВсем  
 
  &АнглийскийСиноним("Start"), ВидноВсем // Процедуре Страт присвоен атрибут ВидноВсем  
 
  // и атрибут АнглийскийСиноним значение которого равно "Start"
 
  // и атрибут АнглийскийСиноним значение которого равно "Start"
  Процедура Старт
+
  Процедура '''Старт'''
 
         //тут какой-то код
 
         //тут какой-то код
 
  КонецПроцедуры
 
  КонецПроцедуры
  
Мы задали для процедуры Старт два атрибута, один созданный нами - '''АнглийскийСиноним''', а другой встроенный - '''ВидноВсем'''.
+
Мы задали для процедуры Старт 2 атрибута, один созданный нами - '''АнглийскийСиноним''', а другой встроенный - '''ВидноВсем'''.
  
 
'''АнглийскийCиноним''' процедуры Старт сможет узнать любая программа (в том числе и эта), которая захочет исследовать программу содержащую процедуру т.е. внешняя программа прочитав значение атрибута АнглийскийСиноним у процедуры Старт получит значение "Start" которое сможет использовать по своему усмотрению.
 
'''АнглийскийCиноним''' процедуры Старт сможет узнать любая программа (в том числе и эта), которая захочет исследовать программу содержащую процедуру т.е. внешняя программа прочитав значение атрибута АнглийскийСиноним у процедуры Старт получит значение "Start" которое сможет использовать по своему усмотрению.
  
Во время компиляции создается экземпляр объект указанного класса-атрибута и сохраняется в сборке в области метаданных вместе с элементом программы, который отмечен этим атрибутом. Любой код, который использует сборку может восстановить экземпляр объекта-атрибута и узнать значения его полей и свойств, получая необходимую дополнительную информацию об элементе программы, который был отмечен этим атрибутом.
+
Во время компиляции создается объект указанного класса-атрибута и сохраняется в сборке в области метаданных вместе с элементом программы, который отмечен этим атрибутом. Любой код, который использует сборку может прочитать атрибут элемента программы и узнать значения его полей и свойств, получая необходимую дополнительную информацию об элементе программы, который был отмечен этим атрибутом.
 +
 
 
Список атрибутов располагается перед элементом программы, к которому он принадлежит, начинается с символа & и разделяется запятыми:
 
Список атрибутов располагается перед элементом программы, к которому он принадлежит, начинается с символа & и разделяется запятыми:
  
Строка 63: Строка 122:
 
  ЭлементПрограммы...
 
  ЭлементПрограммы...
  
Каждый отдельный атрибут — это экземпляр объект указанного класса, созданный оператором Новый, с последующим заполнением полей и свойств этого созданного объекта инициализатором, если необходимо.
+
Каждый отдельный атрибут — это объект (экземпляр класса) указанного класса, созданный оператором '''Новый''', с последующим заполнением полей и свойств этого созданного объекта инициализатором, если необходимо.
  
 
В конструктор атрибута можно передать необходимое количество параметров:
 
В конструктор атрибута можно передать необходимое количество параметров:
  
 
  &Новый ContextClass("МойКласс", "MyClass")
 
  &Новый ContextClass("МойКласс", "MyClass")
Ключевое слово Новый при создании атрибутов не обязательно, просто помните, что оно там присутствует неявно:
+
 
 +
Ключевое слово '''Новый''' при создании атрибутов не обязательно, просто помните, что оно там присутствует неявно:
 
   
 
   
 
  &ContextClass("МойКласс", "MyClass")
 
  &ContextClass("МойКласс", "MyClass")

Текущая версия на 22:22, 29 мая 2022

Устройство атрибута

Технически, атрибуты — это специальные классы, унаследованные от класса Атрибут, который в .Net соответствует классу System.Attribute.

Атрибуты могут что-то значить сами по себе или иметь конструктор, принимающий на хранение дополнительную информацию в виде параметров. Типы параметров конструктора атрибута, а также полей и свойств, ограничены в .Net следующими типами: Цел8, Цел32, Цел64, Байт, Бит32, Бит64, Вещ, ДВещ, Строка, Символ, Булево, Тип, а также это может быть Перечисление одного из указанных типов.

К сожалению, платформа .Net не поддерживает тип Дата в качестве параметра атрибута, но при необходимости дату (как и другие сериализуемые типы) можно представлять строкой.

Написание собственного атрибута и его использование

У атрибута нет логики (т.е. нет методов), он просто хранит несколько параметров, что бы их можно было прочитать в будущем.

Пример Атрибута

Определим простейший атрибут ЕдиницаИзмерений, которым будем помечать физический тип и размерность значений у переменных (например: км/час, кГ, грамм, литр):

&ВидноВсем // Классу ЕденицаИзмерений присваивается атрибут &ВидноВсем
Класс ЕденицаИзмерений Родитель Атрибут
       Поле _ЕдИзмерений тип Строка // Каждый экземпляр этого класса будет иметь одно поле типа Строка в котором будет указанна единица измерений
       &ВидноВсем
       Конструктор(Синоним тип Строка)
               _ЕдИзмерений = ЕдИзмерений
       КонецКонструктора
       &ВидноВсем
       Функция ПолучитьЕдиницаИзмерений() тип Строка
               Возврат _ЕдИзмерений
       КонецФункции
КонецКласса

Присваивание атрибута ЕдиницаИзмереинй - Полю Скорость.

&ЕденицаИзмерений ("км/час"), ВидноВсем // Полю Скорость присвоен атрибут ВидноВсем 
// и атрибут ЕденицаИзмерений значение которого равно "км/час"
Поле Скорость тип Целое = 55  

Т.о. проверив атрибут Поля Скорость, мы получим "км/час"

ЕдиницаИзмеренийСкорости = Скорость.ПолучитьЕдиницаИзмерений()

Строковое поле ЕдиницаИзмеренийСкорости будет равно "км/час"

Пример с фиксированным значением атрибута

&ВидноВсем // Классу атрибута Рубль присваивается атрибут &ВидноВсем и фиксированное значение "Рубль"
Класс Рубль Родитель Атрибут
       Поле _ЕдницаРасчёта тип Строка // Каждый экземпляр этого класса будет иметь одно поле типа Строка в котором будет указанна единица расчёта
       &ВидноВсем
       Конструктор(Синоним тип Строка)
               _ЕдиницаРасчёта = "Рубль"
       КонецКонструктора
       &ВидноВсем
       Функция ПолучитьЕдиницаРасчёта() тип Строка
               Возврат _ЕдиницаРасчёта 
       КонецФункции
КонецКласса

Присваивание атрибута Рубль - Полю Цена.

&Рубль, ВидноВсем // Полю Цена присвоен атрибут ВидноВсем и Рубль
 Поле Цена тип Вещ = 55,7  // Т.е. полю цена при военно вещественное значение 55,7 с атрибутом "Рубль" обозначающим что цена в рублях ,а не копейках или Евро.

Т.о. проверив атрибут Поля Скорость, мы получим "км/час"

ЕденицаРасчётыЦены = Цена.ПолучитьЕдиницаРасчёта

Строковое поле ЕденицаРасчётыЦены будет равно "Рубль" проверив его перед операцией мы ошибочно не прибавим к 10 рублям 25 копеек или 16 Евро

***

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

В стандартной библиотеке Перфоленты почти для всех классов и их членов определены английские синонимы, но компилятор пока ими не умеет ими пользоваться (зарезервировано на будущее)

Практический смысл создавать атрибуты есть тогда, когда есть необходимость из другой программы анализировать элементы текущей.

Например:

  • редактор формы может показывать в палитре свойств только те свойства формы у которых буде установлен атрибут РедактируетсяВПалитреСвойств или не будет атрибута УстаревшееСвойство
  • Программа тестирования может запускать только те методы у которых установлен атрибут Тестировать.
  • Программа выгрузки класса может выгружать только те поля у которых есть атрибут Выгружать и т.д. применений можно много найти...

Определим простейший атрибут АнглийскийСиноним:

&ВидноВсем // Классу АнглийскийСиноним пристраивается атрибут &ВидноВсем
Класс АнглийскийСиноним Родитель Атрибут
       Поле _Синоним тип Строка // Каждый экземпляр этого класса будет иметь одно поле типа Строка 
       &ВидноВсем
       Конструктор(Синоним тип Строка)
               _Синоним = Синоним
       КонецКонструктора
       &ВидноВсем
       Функция ПолучитьСиноним() тип Строка
               Возврат _Синоним
       КонецФункции
КонецКласса

Как видим, кроме наследования от типа Атрибут, других особенностей у класса-атрибута нет. Т.к. объект типа Атрибут - создаётся от обычного класса то ему самому можно присваивать атрибуты. В данном случае всем объектам типа АнглийскийСиноним будет присвоен атрибут &ВидноВсем.

Используем созданный нами атрибут АнглийскийСиноним для одного из методов программы - Процедуры Старт:

&АнглийскийСиноним("Start"), ВидноВсем // Процедуре Страт присвоен атрибут ВидноВсем 
// и атрибут АнглийскийСиноним значение которого равно "Start"
Процедура Старт
       //тут какой-то код
КонецПроцедуры

Мы задали для процедуры Старт 2 атрибута, один созданный нами - АнглийскийСиноним, а другой встроенный - ВидноВсем.

АнглийскийCиноним процедуры Старт сможет узнать любая программа (в том числе и эта), которая захочет исследовать программу содержащую процедуру т.е. внешняя программа прочитав значение атрибута АнглийскийСиноним у процедуры Старт получит значение "Start" которое сможет использовать по своему усмотрению.

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

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

&Атрибут1, Атрибут2, АтрибутН   ЭлементПрограммы...

Для удобства чтения кода обычно ЭлементПрограммы располагают на новой строке вот так:

&Атрибут1, Атрибут2, АтрибутН
ЭлементПрограммы...

Каждый отдельный атрибут — это объект (экземпляр класса) указанного класса, созданный оператором Новый, с последующим заполнением полей и свойств этого созданного объекта инициализатором, если необходимо.

В конструктор атрибута можно передать необходимое количество параметров:

&Новый ContextClass("МойКласс", "MyClass")

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

&ContextClass("МойКласс", "MyClass")

После вызова конструктора можно заполнить значения полей и свойств атрибута с помощью инициализатора:

&Новый ИмпортМетода("kernel32.dll") { .EntryPoint="SetConsoleTitleW", .CharSet=CharSet.Auto, .SetLastError=True}

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

//в этом атрибуте проверим вычисление константных выражений в параметрах
&EnumerationType("Виды"+"Операци"+"и"с,   "Operation"+"Types",   Не Ложь)

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

&Новый ВидноВсем(){}, Новый ВидноСборке(){}

Пустые круглые и фигурные скобки, как и ключевое слово Новый не обязательны:

&ВидноВсем, ВидноСборке

См. также

Ссылки