С# aтрибуты и типы

от автора

Кисточка у художника может быть разной, а можно и совсем без кисточки. В С++ типы исчезали после трансляции, а вот в C# они не исчезают и могут быть использованы на этапе выполнения. С# — это располневшая на мелкософтах Дельфи и основная причина юзанья атрибутов с типами — PropertyGrid, бывший TValueListEditor. Ну а потом можно придти к не очевидному выводу, что атрибуты с типами — просто и удобно.

Раньше методы, поля и свойства класса были чисто феней промеж кодерами, можно было сказать метод, а можно — функция, можно — поле, а можно — просто переменная. Но коль скоро есть тип в памяти, то к нему можно обращаться, а обращаясь нужно использовать точные термины. От любого объекта можно получить его тип, а от типа можно получить имена полей, свойств и методов, а по именам можно получить значение поля — т.е. уже другой объект, или вызвать метод со всеми параметрами и возвращаемым значением.

class X     {         class A         {             public int f1;             public int p1 { get; set; }             public int m1(string s, int i) { return (0); }         }         X()         {             A a = new A();             Type t = a.GetType();              FieldInfo fi = t.GetField("f1");             object of = fi.GetValue(a);              PropertyInfo pi = t.GetProperty("p1");             MethodInfo mpi = pi.GetGetMethod();             object ompi = mpi.Invoke(a, null);              MethodInfo mi = t.GetMethod("m1");             object om = mi.Invoke(a, new object[] { "param1", 2 });         }     } 

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

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

У каждого типа есть список атрибутов, этот список может быть пуст, а может быть и полон. Вот тут и начинается самое интересное. Оказывается у каждого объекта свой собственный уникальный тип. Иначе говоря, две переменные типа int имеют два разных типа. Эти типы могут быть одинаковы, а могут быть и различны, и различаться они будут списком атрибутов. Понятно, что exe-шник не переполняется повторяющимися типами, реализация идет через ссылки, но в дырявом представлении уровня кодера это именно так.

    class X     {         class ATTR1 : Attribute { public ATTR1() { } }         class ATTR2 : Attribute { public ATTR2() { } }         class A         {             [ATTR1]             public int i1;              [ATTR2]             public int i2;          }         X()         {              object[] ai1 = a.i1.GetType().GetCustomAttributes(false);             object[] ai2 = a.i2.GetType().GetCustomAttributes(false);         }     } 

У объектов никаких атрибутов нет, атрибуты только у типов. От каждого объекта мы можем получить его тип, а в типе найти атрибуты. Но коль скоро тип у каждого объекта уникальный, то можно сказать, что у объекта есть атрибуты. Однако можно так же сказать, что объект описан в некотором типе, а в этом типе к этому объекту так же приписаны атрибуты. Таким образом, у объекта есть два списка атрибутов – список по его собственному типу, и список по типу, в котором этот объект описан.

    class X     {         class ATTR1 : Attribute { public ATTR1() { } }         class ATTR2 : Attribute { public ATTR2() { } }          [ATTR1]         class A { }          [ATTR2]         A a;                  X()         {             a = new A();              object[] inner = a.GetType().GetCustomAttributes(false);             object[] outer = this.GetType().GetField("a").GetCustomAttributes(false);         }     } 

Атрибуты есть не только у полей, но и у методов, и у свойств. Чтобы использовать атрибуты их сперва нужно найти у объекта. Когда мы ищем атрибуты у объекта, то мы должны выбрать соответствующий список, а когда прописываем атрибуты – соответственно писать в тот тип, который следует. Зачастую кодер на всякий случай проверяет атрибуты и там и там, а при противоречии атрибутов отдает приоритет атрибуту поля перед атрибутом типа.

Первобытные кодеры полагали, что главное это прогу закодить. Потом предки пришли к тому, что главное это данные заструктурить. В наш просвещенный век универсальные проги бороздят просторы структурированного океана данных, наводя там новый порядок. Одна из таки программ – PropertyGrid, которая показывает на экране дерево данных с возможностью их изменить. Как найдет public property – так сразу и покажет. А если property такое нестандартное, что его ни посмотреть, ни отредактировать, то PropertyGrid поищет атрибутик с описанием класса, которым можно посмотреть и поправить property. А если не найдет – то и показывать не станет. А че, СУБД давно хранят типы своих данных и живут припеваючи, почему бы и проге их не хранить – памяти на компах теперь складывать некуда, а на скоростях можно и неуправляемый кусочек закодить.

Известные глюки.

Усё работает внутри c#, но стоит выставить в OLE (COM, ActiveX), как сразу теряются некоторые атрибуты, скорее всего при переходе от одной c# dll к другой. Например когда сама полянка (field) описана в одной dll, а ее тип с атрибутом — в другой, при чем атрибут то не пропадет, пропадут его полянки — он же тоже класс в свою очередь. Трудно определить где конкретно глюк. Вероятнее всего CCW вальтует. CCW — это такое волшебное слово, означающее обёртку со сборщиком мусора для неуправляемого вызова. Шарповцы полагают, что кодеры будут писать на шарпе и изредка подтягивать свои старые наработки на плюсах, а сами кодеры полагают, что они будут сопровождать своих монстров допиливая к ним кусочки на шарпе.

ссылка на оригинал статьи http://habrahabr.ru/post/267515/


Комментарии

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

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