Кисточка у художника может быть разной, а можно и совсем без кисточки. В С++ типы исчезали после трансляции, а вот в C# они не исчезают и могут быть использованы на этапе выполнения. С# — это располневшая на мелкософтах Дельфи и основная причина юзанья атрибутов с типами — PropertyGrid, бывший TValueListEditor. Ну а потом можно придти к не очевидному выводу, что атрибуты с типами — просто и удобно.
Раньше методы, поля и свойства класса были чисто феней промеж кодерами, можно было сказать метод, а можно — функция, можно — поле, а можно — просто переменная. Но коль скоро есть тип в памяти, то к нему можно обращаться, а обращаясь нужно использовать точные термины. От любого объекта можно получить его тип, а от типа можно получить имена полей, свойств и методов, а по именам можно получить значение поля — т.е. уже другой объект, или вызвать метод со всеми параметрами и возвращаемым значением.
Таким образом, мы получили альтернативный запутаистичный способ программирования, когда мы можем писать не сами переменные, а их строковые имена. Строковые имена можно менять.
Каждый объект имеет две ипостаси: с одной стороны он есть поле какого то типа, а с другой стороны он сам имеет свой тип, в котором могут быть разные поля. Типы на этапе выполнения изменить нельзя, кроме как обратиться по адресу в памяти хакерским методом.
У каждого типа есть список атрибутов, этот список может быть пуст, а может быть и полон. Вот тут и начинается самое интересное. Оказывается у каждого объекта свой собственный уникальный тип. Иначе говоря, две переменные типа int имеют два разных типа. Эти типы могут быть одинаковы, а могут быть и различны, и различаться они будут списком атрибутов. Понятно, что exe-шник не переполняется повторяющимися типами, реализация идет через ссылки, но в дырявом представлении уровня кодера это именно так.
У объектов никаких атрибутов нет, атрибуты только у типов. От каждого объекта мы можем получить его тип, а в типе найти атрибуты. Но коль скоро тип у каждого объекта уникальный, то можно сказать, что у объекта есть атрибуты. Однако можно так же сказать, что объект описан в некотором типе, а в этом типе к этому объекту так же приписаны атрибуты. Таким образом, у объекта есть два списка атрибутов – список по его собственному типу, и список по типу, в котором этот объект описан.
Атрибуты есть не только у полей, но и у методов, и у свойств. Чтобы использовать атрибуты их сперва нужно найти у объекта. Когда мы ищем атрибуты у объекта, то мы должны выбрать соответствующий список, а когда прописываем атрибуты – соответственно писать в тот тип, который следует. Зачастую кодер на всякий случай проверяет атрибуты и там и там, а при противоречии атрибутов отдает приоритет атрибуту поля перед атрибутом типа.
Первобытные кодеры полагали, что главное это прогу закодить. Потом предки пришли к тому, что главное это данные заструктурить. В наш просвещенный век универсальные проги бороздят просторы структурированного океана данных, наводя там новый порядок. Одна из таки программ – PropertyGrid, которая показывает на экране дерево данных с возможностью их изменить. Как найдет public property – так сразу и покажет. А если property такое нестандартное, что его ни посмотреть, ни отредактировать, то PropertyGrid поищет атрибутик с описанием класса, которым можно посмотреть и поправить property. А если не найдет – то и показывать не станет. А че, СУБД давно хранят типы своих данных и живут припеваючи, почему бы и проге их не хранить – памяти на компах теперь складывать некуда, а на скоростях можно и неуправляемый кусочек закодить.
Известные глюки.
Усё работает внутри c#, но стоит выставить в OLE (COM, ActiveX), как сразу теряются некоторые атрибуты, скорее всего при переходе от одной c# dll к другой. Например когда сама полянка (field) описана в одной dll, а ее тип с атрибутом — в другой, при чем атрибут то не пропадет, пропадут его полянки — он же тоже класс в свою очередь. Трудно определить где конкретно глюк. Вероятнее всего CCW вальтует. CCW — это такое волшебное слово, означающее обёртку со сборщиком мусора для неуправляемого вызова. Шарповцы полагают, что кодеры будут писать на шарпе и изредка подтягивать свои старые наработки на плюсах, а сами кодеры полагают, что они будут сопровождать своих монстров допиливая к ним кусочки на шарпе.
Раньше методы, поля и свойства класса были чисто феней промеж кодерами, можно было сказать метод, а можно — функция, можно — поле, а можно — просто переменная. Но коль скоро есть тип в памяти, то к нему можно обращаться, а обращаясь нужно использовать точные термины. От любого объекта можно получить его тип, а от типа можно получить имена полей, свойств и методов, а по именам можно получить значение поля — т.е. уже другой объект, или вызвать метод со всеми параметрами и возвращаемым значением.
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.GetType().GetField("i1").GetCustomAttributes(false);
object[] ai2 = a.GetType().GetField("i2").GetCustomAttributes(false);
}
}
У объектов никаких атрибутов нет, атрибуты только у типов. От каждого объекта мы можем получить его тип, а в типе найти атрибуты. Но коль скоро тип у каждого объекта уникальный, то можно сказать, что у объекта есть атрибуты. Однако можно так же сказать, что объект описан в некотором типе, а в этом типе к этому объекту так же приписаны атрибуты. Таким образом, у объекта есть два списка атрибутов – список по его собственному типу, и список по типу, в котором этот объект описан.
class X
{
class ATTR1 : Attribute { public ATTR1() { } }
class ATTR2 : Attribute { public ATTR2() { } }
[ATTR1]
public class A { }
[ATTR2]
public 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 — это такое волшебное слово, означающее обёртку со сборщиком мусора для неуправляемого вызова. Шарповцы полагают, что кодеры будут писать на шарпе и изредка подтягивать свои старые наработки на плюсах, а сами кодеры полагают, что они будут сопровождать своих монстров допиливая к ним кусочки на шарпе.
Комментарии (11)
Karroplan
23.09.2015 11:38+6это прорыв udaff.com на хабр?
whitepen
23.09.2015 14:56-4Конечно, исходник проги однозначно ее определяет, но вот прочитать его никак нельзя, если он чуть больше страницы. Для описания программы поневоле приходится использовать литературно-художественные понятия, такие как виртуальность, метод доступа, драйвер, интерфейс… которые вообще говоря ничего определенного не обозначают, или обозначают все что угодно.
lair
Феерическая терминологическая каша.
Нет, основная причина сохранения информации о типах вплоть до времени выполнения — это то, что код управляемый, а для управления нужна информация. Ну и reflection во всех его проявлениях — очень удобен.
Нет. Каждый объект — это объект (определенного типа, конечно же). Он не поле, он объект. Поле может содержать ссылку на объект (для ссылочных типов), или сам объект (для типов-значений при определенных условиях).
А вот и нет. Они имеют один и тот же тип —
typeof(int)
.Оба вызова вернут одно и то же. А чтобы получить
[ATTR1]
и[ATTR2]
, надо запрашивать атрибуты уFieldInfo
.Тоже нет. Атрибуты есть у типов, у членов типов, у параметров и возвращаемых значений методов и даже у сборок.
А вот у объектов никаких атрибутов нет.
whitepen
Пример поправил. Строгая терминология полезна тем, кто знает C#, но им совершенно бесполезна моя статья. А вот тем, кто не знает терминов шарпа, а писал на плюсах, например, в самый раз. Вы наверное изволили заметить, что статья весьма коротка и не включает ничего. Зато писать уже можно.
lair
… и как же вы теперь обосновываете свое заявление «две переменные типа int имеют два разных типа»?
Зачем загаживать людям мозги ошибочной информацией?
Но не нужно.
whitepen
Писать совершенные, взвешенные и продуманные суждения означает не писать ничего и никогда. Так устроен этот мир.
Атрибут принадлежит типу, и если типы различаются списком атрибутов — значит они различны. Здесь кроется большая опасность, так как нужно думать когда атрибут выполняется — он ведь исполняемый класс в отличие от типа. Полагаю что шарповцы не смогли исключить все ошибки и далее не смогут.
lair
Да нет же, с чего вы это взяли? Атрибут может принадлежать как типу, так и члену типа, параметру и возвращаемому значению, и сборке целиком.
А где вы видите, что типы различаются списком атрибутов? Покажите конкретный пример кода и его вывод.
whitepen
Экий вы право же продвинутый. Я сознательно написал «переменная», что вообще говоря в терминах шарпа совсем никак. А потом долго описывал какие то ипостаси, которые так же никак, и связывал объект с типом внешним и внутренним на этапе выполнения, хотя нет ни внешних, ни внутренних типов. И писал про дырявые представления — т.е. изначально неверные представления. Чисто для понимания, а вовсе не для документирования. А вы, как я полагаю, решили блеснуть глубиной знаний шарпа, не так ли?
lair
Почему «никак»? В C# есть переменные.
Не надо «для понимания» писать изначально неверные вещи.
whitepen
О, да вы, батенька, крупный троль. Только вот увидал. Извините за недоброкачественные продукты питания.
Alvaro
Тип int никак не изменился от того, что у поля класса A есть атрибут ATTR1