С Новым годом! Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.85/456: Рейтинг темы: голосов - 456, средняя оценка - 4.85
Заблокирован
1

Отражение, метаданные, атрибуты

10.10.2010, 20:57. Показов 88800. Ответов 1

Author24 — интернет-сервис помощи студентам
Одной из особенностей платформы .NET является то, что программы, написанные под неё, не превращаются в монотонные последовательности машинных инструкций, разобрать которые - весьма нетривиальная задача в общем случае, а наоборот, сохраняют первоначальную структуру (включая иерархию классов и т.п.), а также снабжаются подробной информацией о том, где и что лежит и что из себя представляет. Такая информация, такие данные о данных (о программе), называются метаданными.

Часть метаданных генерируется компилятором. Часть можно задавать самому в программном коде при помощи атрибутов. Используется она тоже всюду: и средой исполнения, и программистом (по мере необходимости с помощью системы отражения (reflection)).

Далее для примеров я буду использовать такие типы:
C#
1
2
3
class A { }
class B : A { }
class C { }
Оператор is.

Оператор is позволяет определить, совместим ли объект с указанным типом.
Если ссылка содержит null, оператор is вернёт false.
Объявление неявного оператора преобразования из типа в тип (в данном случае из A в C и/или обратно) никак на оператор is не повлияет.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
A objA = new A();
B objB = new B();
 
// True - потому что объект objA является экземпляром класса A.
Console.WriteLine(objA is A);
 
// False - потому что объект objA не является экземпляром класса C.
Console.WriteLine(objA is C);
 
// True - потому что объект objA является экземпляром класса,
// унаследованным от класса A. Потому objB можно приводить к типу A.
Console.WriteLine(objB is A);
 
// False - потому что объект objB никаким образом не связан с классом C.
Console.WriteLine(objB is C);
Оператор as.

Оператор as является оператором приведения, позволяя приводить объект к любому типу. В случае, если приведение не удалось, возвращается null.

C#
1
2
object objB = new B();
A objA = objB as A;
Привести к типу можно и вот таким образом:
C#
1
2
object objB = new B();
A objA = (A)objB;
с той лишь разницей, что в этом случае при неудачном приведении будет брошено исключение InvalidCastException.

Также нужно заметить, что оператор as не выполняет, например, преобразования определённые пользователем.

Оператор typeof и класс System.Type.

Класс System.Type описывает тип данных и с помощью своих методов и свойств открывает доступ к чтению метаданных этого типа. Получить экземпляр данного класса для типа можно несколькими способами:

C#
1
2
3
// С помощью оператора typeof получаем объект,
// описывающий тип, собственно по самому типу
Type t = typeof (A);
C#
1
2
3
4
// Базовый класс System.Object имеет метод GetType(), который возвращает
// объект класса Type для данной сущности
A obj = new A();
Type t = obj.GetType();
C#
1
2
// Класс Type имеет статический метод GetType(), позволяющий получить тип по его имени
Type t = Type.GetType("A");
Здесь "A" - полный путь к типу со всеми пространствами имён.

Некоторые свойства-предикаты класа Type:
  • IsAbstract - является ли тип абстрактным классом.
  • IsArray - является ли тип массивом.
  • IsClass - является ли тип классом (а не интерфейсом или структурой).
  • IsInterface - является ли тип интерфейсом.
  • IsEnum - является ли тип перечислением.
  • IsValueType - является ли тип структурой (а, если точнее, то наследником System.ValueType, а это все нессылочные типы).
  • и т.д.
Пример:
C#
1
2
// True - тип A является классом
Console.WriteLine(typeof(A).IsClass);
Также стоит упомянуть свойство Name, возвращающее имя типа. Может быть полезно при отладке:
C#
1
2
// Выведет "A"
Console.WriteLine(typeof(A).Name);
Кроме полезных свойств класс Type содержит также немало методов, также крайне полезных. Например, метод GetMethods() возвращает массив объектов класса MethodInfo. Класс MethodInfo по сути служит тем самым описателем для метода, каким является класс Type для типа. Т.е. GetMethods() возвращает по описателю для каждого метода в данном типе.

Для примера расширим класс A, добавив в него несколько методов:
C#
1
2
3
4
5
6
class A
{
public void MethodHello() { }
public void MethodWorld() { }
private void Abc() { }
}
А теперь выведем их имена на консоль:
C#
1
2
3
4
5
Type t = typeof (A);
MethodInfo[] methods = t.GetMethods();
 
foreach (MethodInfo method in methods)
Console.WriteLine(method.Name);
После выполнения данного кода увидим следующее:
Код
MethodHello
MethodWorld
ToString
Equals
GetHashCode
GetType
Это все методы, которые есть у нашего класса A. В том числе и методы, унаследованные (в данном случае от класса System.Object). А, например, метода Abc в списке не оказалось, потому что он является приватным.

Само собой процессом получения методов можно управлять. Для этого в классе Type есть перегруженная версия метода GetMethods, которая принимает в качестве параметра флаги задаваемые перечислением BindingFlags. Например, для того, чтобы вывести и публичные и приватные методы, нужно использовать флаги Public и NonPublic:
C#
1
MethodInfo[] methods = typeof(A).GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
Кроме метода GetMethods(), есть также метод GetMethod(), позволяющий получить метод по имени. Например, так:
C#
1
MethodInfo method = typeof (A).GetMethod("MethodHello");
Кроме методов класса Type для получения методов типа, есть также следующие методы:
  • GetMembers() и GetMember() - позволяют получить любые члены типа, включая методы, свойства, конструкторы, вложенные типы и т.д.
  • GetInterfaces() и GetInterface() - позволяют получить интерфейсы, реализованные типом.
  • GetNestedTypes() и GetNestedType() - позволяют получить вложенные типы. Т.е. для класса
    C#
    1
    2
    3
    4
    
    class X
    {
    public class Y { }
    }
    эти методы позволяют получить объект описыващий тип Y.
  • GetProperties() и GetProperty() - позволяют получить свойства.
  • и т.д.

Вызов члена по его *Info.

Понятное дело, что хорошо иметь под рукой инструмент позволяющий получать информацию о всех типах и их членах. Но всё бы было не так хорошо, если бы на этом всё и заканчивалось. На самом деле все эти классы MethodInfo, PropertyInfo и прочие *Info позволяют не только получить информацию, но и нахально ею воспользоваться. Например, метод можно вызвать:
C#
1
2
3
A objA = new A();
MethodInfo method = objA.GetType().GetMethod("MethodHello");
method.Invoke(objA, null);
Происходит это с помощью метода Invoke класса MethodInfo. Первый аргумент - объект типа, в котором объявлен метод, который мы хотим вызвать (для статических методов, понятное дело, объект не нужен и можно указать null). Второй аргумент - аргументы вызываемого метода (так как у нашего метода их нет, передаём null).

Аналогично со свойствами. Допустим, есть у нас класс
C#
1
2
3
4
class ClassWithProperty
{
public int Prop { get; set; }
}
тогда можно к его свойству Prop обратиться так:
C#
1
2
3
ClassWithProperty obj = new ClassWithProperty();
PropertyInfo property = obj.GetType().GetProperty("Prop");
property.SetValue(obj, 1, null);
Метод SetValue() класса PropertyInfo позволяет записать значение в свойство (есть также метод GetValue(), с помощью которого можно значения получать). Первый аргумент - объект, с которым хотим работать. Второй аргумент - собственно значение, которое хотим установить. Третий же аргумент позволяет задавать индексы для индексатора (но так как у нас простое свойство, то ставим просто null).

Также стоит упомянуть о конструкторах. Получив объект класса ConstructorInfo, можно, как не сложно догадаться, вызвав его, создать объект.
C#
1
2
Type t = typeof (A);
A obj = (A) t.GetConstructors()[0].Invoke(null);
Что это даёт? Например, возможность создавать объекты по их строковому имени. Вот так:
C#
1
2
Type t = Type.GetType("A");
A obj = (A) t.GetConstructors()[0].Invoke(null);
На самом деле, это не единственный и не самый простой способ создать объект по имени класса. Ниже я напишу, как это сделать проще.

Атрибуты.

Атрибуты - это средство привязки информации к различным сущностям: методам, свойствам, типам и даже целым сборкам. По своей сути атрибут - это экземпляр класса унаследованного от System.Attribute.

Присоединить атрибут к сущности можно путём добавления его имени перед ней в квадратных скобках:
C#
1
2
3
4
5
public class A
{
[ObsoleteAttribute]
public void B() { }
}
В данном случае предопределённый атрибут ObsoleteAttribute указывает на то, что метод B является устаревшим и его использовать не стоит. Указывает он это среде (IDE), которая соответствующим образом использование такого метода подчеркнёт и компилятору, который выдаст предупреждение.

В C# есть небольшое упрощение: слово Attribute можно не писать, компилятор сам подставит что нужно:
C#
1
2
3
4
5
public class A
{
[Obsolete]
public void B() { }
}
Бывают также атрибуты, которые принимают некоторые значения в качестве параметров. В таком случае эти значения нужно указать в круглых скобках после имени атрибута.

Можно, безусловно, создавать свои атрибуты. Для этого просто унаследуемся от класса System.Attribute:
C#
1
2
3
4
5
6
7
8
9
class ColoredAttribute : Attribute
{
public ColoredAttribute(ConsoleColor color)
{
Color = color;
}
 
public ConsoleColor Color { get; private set; }
}
Этот класс позволит задавать "цвет" для любой сущности вот таким образом:
C#
1
2
3
4
5
6
7
8
class A
{
[Colored(ConsoleColor.Red)]
public void X() { }
 
[Colored(ConsoleColor.Green)]
public void Y() { }
}
Понятно, что о целях нашего атрибута знаем только мы, потому нужно написать код, который соответствующие методы выведет в консоль заданным нами с помощью атрибута цветом. Для этого обратимся опять к System.Type:

C#
1
2
3
4
5
6
7
8
9
10
Type t = typeof (A);
foreach (MethodInfo method in t.GetMethods())
{
object[] attribs = method.GetCustomAttributes(typeof(ColoredAttribute), false);
if (attribs.Length == 0) continue;
 
ColoredAttribute attrib = (ColoredAttribute)attribs[0];
Console.ForegroundColor = attrib.Color;
Console.WriteLine(method.Name);
}
Данный код выведет в консоль имя метода X красным цветом и имя метода Y зелёным. Получили мы атрибуты связанные с методами при помощи метода GetCustomAttributes(). Таким же образом можно получать атрибуты и для других сущностей.

При создании своего класса атрибутов стоит обратить внимание на предопределённый атрибут AttributeUsage. С помощью него можно задать область применимости своего атрибута. Например, если определим наш класс таким образом
C#
1
2
3
4
5
[AttributeUsage(AttributeTargets.Method)]
class ColoredAttribute : Attribute
{
// ....
}
то использовать атрибут ColoredAttribute можно будет только на методах.

Ещё хочу упомянуть очень полезный в хозяйстве атрибут Conditional. Он позволяет задавать условные методы, которые будут вызываться лишь в том случае, если соответствующий идентификатор определён с помощью директивы #define.

В этом примере метод World() будет вызываться только в случае, если определён идентификатор TEST. Если убрать из кода #define TEST, сообщения Hello на консоли мы не увидим.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#define TEST
 
using System;
using System.Diagnostics;
 
class Program
{
[Conditional("TEST")]
static void World()
{
Console.WriteLine("Hello");
}
 
static void Main()
{
World();
}
}
38
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
10.10.2010, 20:57
Ответы с готовыми решениями:

Атрибуты класса и атрибуты объекта
в чем разница атрибута класса и атрибута объекта? препод задал вопрос : "функция доступа set()...

Метаданные
Хотелось бы узнать как работает тег meta. На одном ресурсе прочитал следующее: Правда это или...

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

Метаданные
как записывать и редактировать метаданные в медиафайлах?Где вообще прочитать про метаданные в С#. В...

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

1
tezaurismosis
24.08.2015, 10:59     Отражение, метаданные, атрибуты
  #2
 Комментарий модератора 
Если вы нашли неточность или опечатку, хотите что-то добавить к написанному в статье - обсуждение ведётся в отдельной теме:
https://www.cyberforum.ru/faq/thread1519084.html
0
24.08.2015, 10:59
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
24.08.2015, 10:59
Помогаю со студенческими работами здесь

Метаданные файла
Можно ли каким-либо образом прочитать/изменить метаданные у файла?

Метаданные MP3
Всем добрый день. Подскажите пожалуйста, как можно вытащить из файла мп3 метаданные? В частности...

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

FPDF метаданные
смысл вопроса в кодировке все файлы моего сайта в UTF-8 делаю с помощью fpdf пдф документ,...

Выбрать метаданные
Привет всем! Подскажите, пожалуйста, как можно извлечь данные из 1с 7.7 и 8.1: Справочник1...

Метаданные изображения
Нужно получить некоторую информацию из .jpg файла (exif)/ Нашёл класс "PropertyItem" пространства...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
2
Закрытая тема Создать тему
Блоги программистов
Как перейти с Options API на Composition API в Vue.js
BasicMan 06.01.2025
Почему переход на Composition API актуален В мире современной веб-разработки фреймворк Vue. js продолжает эволюционировать, предлагая разработчикам все более совершенные инструменты для создания. . .
Архитектура современных процессоров
inter-admin 06.01.2025
Процессор (центральный процессор, ЦП) является основным вычислительным устройством компьютера, которое выполняет обработку данных и управляет работой всех остальных компонентов системы. Архитектура. . .
История создания реляционной модели баз данных, правила Кодда
Programming 06.01.2025
Предпосылки создания реляционной модели В конце 1960-х годов компьютерная индустрия столкнулась с серьезными проблемами в области управления данными. Существовавшие на тот момент модели данных -. . .
Полезные поделки на Arduino, которые можно сделать самому
raxper 06.01.2025
Arduino как платформа для творчества Arduino представляет собой удивительную платформу для технического творчества, которая открывает безграничные возможности для создания уникальных проектов. Эта. . .
Подборка решений задач на Python
IT_Exp 06.01.2025
Целью данной подборки является предоставление возможности ознакомиться с различными задачами и их решениями на Python, что может быть полезно как для начинающих, так и для опытных программистов. . . .
С чего начать программировать микроконтроллер­­ы
raxper 06.01.2025
Введение в мир микроконтроллеров Микроконтроллеры стали неотъемлемой частью современного мира, окружая нас повсюду: от простых бытовых приборов до сложных промышленных систем. Эти маленькие. . .
Из чего собрать игровой компьютер
inter-admin 06.01.2025
Сборка игрового компьютера требует особого внимания к выбору комплектующих и их совместимости. Правильно собранный игровой ПК не только обеспечивает комфортный геймплей в современных играх, но и. . .
Обновление сайта www.historian.b­y
Reglage 05.01.2025
Обещал подвести итоги 2024 года для сайта. Однако начну с того, что изменилось за неделю. Добавил краткий урок по последовательности действий при анализе вредоносных файлов и значительно улучшил урок. . .
Как использовать GraphQL в C# с HotChocolate
Programming 05.01.2025
GraphQL — это современный подход к разработке API, который позволяет клиентам запрашивать только те данные, которые им необходимы. Это делает взаимодействие с API более гибким и эффективным по. . .
Модель полного двоичного сумматора с помощью логических операций (python)
AlexSky-coder 04.01.2025
def binSum(x:list, y:list): s=^y] p=x and y for i in range(1,len(x)): s. append((x^y)^p) p=(x and y)or(p and (x or y)) return s x=list() y=list()
Это мы не проходили, это нам не задавали...(аси­­­­­­­­­­­­­­­­­­­­х­р­о­н­н­ы­й счётчик с управляющим сигналом задержки).
Hrethgir 04.01.2025
Асинхронный счётчик на сумматорах (шестиразрядный по числу диодов на плате, но наверное разрядов будет больше - восемь или шестнадцать, а диоды на старшие), так как триггеры прошли тестирование и. . .
Руководство по созданию бота для Телеграм на Python
IT_Exp 04.01.2025
Боты для Телеграм представляют собой автоматизированные программы, которые выполняют различные задачи, взаимодействуя с пользователями через интерфейс мессенджера. В данной статье мы рассмотрим,. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru