Описание метаданных
В обоих языках (в Java — начиная с версии 5) имеются встроенные средства для некоторого их расширения, для описания так называемых метаданных — данных, описывающих элементы кода. Это специальные модификаторы у типов, элементов типов и параметров операций, называемые в Java аннотациями (annotations), а в C# — атрибутами (attributes). Один элемент кода может иметь несколько таких модификаторов.
Такие данные служат для указания дополнительных свойств классов, полей, операций и параметров операций. Например, можно пометить специальным образом поля класса, которые должны записываться при преобразовании объекта этого класса в поток байтов для долговременного хранения или передачи по сети. Можно пометить методы, которые должны работать только в рамках транзакций или, наоборот, только вне транзакций.
Метаданные служат встроенным механизмом расширения языка, позволяя описывать простые дополнительные свойства сущностей этого языка в нем самом, не разрабатывая каждый раз специализированные трансляторы. Обработка метаданных должна, конечно, осуществляться дополнительными инструментами, но такие инструменты могут быть достаточно просты — им не нужно реализовывать функции компилятора исходного языка.
В обоих языках аннотации могут иметь структуру — свойства или параметры, которым можно присваивать значения. Эту структуру можно определить в описании специального аннотационного типа.
В приведенных ниже примерах определяются несколько типов аннотаций, которые затем используются для разметки элементов кода. Класс A помечен аннотацией, имеющей указанные значения свойств, оба метода помечены простой аннотацией (указывающей, например, что такой метод должен быть обработан особым образом), кроме того, метод n() помечен еще одной аннотацией. Параметр метода n() также помечен простой аннотацией.
@interface SimpleMethodAnnotation {} @interface SimpleParameterAnnotation{} @interface ComplexClassAnnotation { int id(); String author() default "Victor Kuliamin"; String date(); } @interface AdditionalMethodAnnotation { String value() default ""; } @ComplexClassAnnotation ( id = 126453, date = "23.09.2005" ) public class A { @SimpleMethodAnnotation public void m() { ... } @SimpleMethodAnnotation @AdditionalMethodAnnotation ( value = "123" ) public void n (@SimpleParameterAnnotation int k) { ... } } | class SimpleMethodAttribute : Attribute {}
class SimpleParameterAttribute : Attribute {} class ComplexClassAttribute : Attribute { public int id; public String author = "Victor Kuliamin"; public String date; } class AdditionalMethodAttribute : Attribute { public String value = ""; } [ComplexClassAttribute ( id = 126453, date = "23.09.2005" )] public class A { [SimpleMethodAttribute] public void m() { ... } [SimpleMethodAttribute, AdditionalMethodAttribute (value = "123")] public void n ([SimpleParameterAttribute] int k) { ... } } | ||
В Java аннотации могут помечать также пакеты (т.е. использоваться в директиве декларации пакета, к которому относится данный файл), декларации локальных переменных и константы перечислимых типов. |
В C# могут быть описаны глобальные атрибуты, помечающие сборку, в рамках кода которой они встречаются. Такие атрибуты помещаются вне описаний пространств имен. Также атрибутами могут помечаться отдельные методы доступа к свойствам, индексерам и событиям. | ||
Аннотационный тип декларируется с модификатором @interface и неявно наследует интерфейсу java.lang.annotation.Annotation. Такой тип не может иметь типовых параметров или явным образом наследовать другому типу. |
Атрибутный тип описывается как класс, наследующий System.Attribute или его наследнику. Такой тип не может иметь типовых параметров. | ||
Свойства аннотационного типа описываются как абстрактные методы без параметров, с возможным значением по умолчанию. При определении значений свойств аннотации через запятую перечисляются пары <имя свойства> = <значение>. Помимо свойств, в аннотационном типе могут быть описаны константы (public static final поля) и вложенные типы, в том числе аннотационные. |
Свойства атрибутного типа могут быть именованными параметрами и позиционными параметрами. Позиционные параметры определяются при помощи конструкторов атрибутного типа. Именованные параметры определяются как доступные для чтения и записи нестатические поля и свойства атрибутного типа. При определении значений свойств атрибута сначала через запятую перечисляются значения позиционных параметров, а затем пары <имя именованного параметра> = <значение>. В атрибутном типе могут быть описаны такие же элементы, как и в обычном классе. Ниже приведен пример использования позиционного параметра. class ClassAttribute : Attribute { public ClassAttribute(int id) { this.id = id; } int id; public string value; } [ClassAttribute(4627, value = "")] public class A { ... } | ||
Свойство аннотационного типа может иметь примитивный тип, тип String, Class, экземпляр шаблонного типа Class, перечислимый тип, аннотационный тип или быть массивом элементов одного из перечисленных типов. |
Свойство атрибутного типа может иметь один из типов bool, byte, char, double, float, int, long, short, string, object, System.Type, перечислимый тип или быть массивом элементов одного из таких типов. У атрибутов может указываться цель, к которой они привязываются. Для атрибутов, помещаемых вне рамок пространств имен, указание такой цели — assembly — обязательно. [assembly : MyAttribute ( id = 4627, author = "Victor Kuliamin" )] В C# принято соглашение, согласно которому окончание Attribute в именах атрибутных типов может отбрасываться при использовании атрибутов такого типа. Поэтому, имея атрибутный тип ClassAttribute, можно использовать в атрибутах как полное имя ClassAttribute, так и сокращенное Class. В последнем случае компилятор будет пытаться найти атрибутный тип с именем Class или с именем ClassAttribute. При этом возможна неоднозначность — оба таких типа могут существовать в рамках сборки и доступных библиотек. Для ее разрешения можно использовать точное имя атрибутного типа с префиксом @. Увидев атрибут @Class, компилятор будет искать атрибутный тип в точности с именем Class. |