Разбираемся с рефлексией на примерах в C#

Приветствую всех, сегодня поговорим о рефлексии, для чего она нужна, ее применения. Тема эта очень интересная, и ее методы использования часто приходится применять в больших проектах.

Рефлексия (отражение) — это процесс, во время которого программа может отслеживать и модифицировать собственную структуру и поведение во время выполнения, это своего рода процесс обнаружения типов во время выполнения.

Рефлексия позволяет: перечислять члены типа, создавать новые экземпляры объекта, запускать на выполнение члены объекта, извлекать информацию о типе, извлекать информацию о сборке, исследовать пользовательские атрибуты, примененные к типу, создавать и компилировать новые сборки.

Метаданные описывают все классы и члены классов, определённые в сборке, а также классы и члены классов, которые текущая сборка вызывает из другой сборки.

Манифест сборки— коллекция данных, с описанием того, как элементы любой сборки (статической или динамической) связаны друг с другом. Манифест сборки содержит все
метаданные, необходимые для задания требований сборки к версиям и удостоверения безопасности, а также все метаданные, необходимые для определения области действия сборки и разрешения ссылок на ресурсы и классы. Манифест сборки может храниться в PE-файле (EXE или DLL) с кодом MSIL или же в отдельном PE-файле, содержащем только данные манифеста.

Модули — это контейнеры типов, расположенные внутри сборки. Модуль может быть контейнером в простой, или многофайловой сборке. Несколько модулей в одной сборке применяются в редких случаях, когда нужно добавить код на разных языках в одну сборку или обеспечить поддержку выборочной загрузки модулей.

Парадигма программирования, положенная в основу отражения, называется рефлексивным программированием. Это один из видов метапрограммирования.

System.Reflection — Пространство имен содержит типы, предназначенные для извлечения сведений о сборках, модулях, членах, параметрах и других объектах в управляемом коде путем обработки их метаданных. Эти типы также можно использовать для работы с экземплярами загруженных типов, например для подключения событий или вызова методов.

Класс Type.

Type является корневым классом для функциональных возможностей рефлексии и основным способом доступа к метаданным. С помощью членов класса Type можно
получить сведения об объявленных в типе элементах: конструкторах, методах, полях, свойствах и событиях класса, а также о модуле и сборке, в которых развернут данный класс.

Способы получения экземпляра:

Таким образом мы получим ссылку на объект Type, содержащий информацию о целевом типе .

В типе System. Туре находятся перегруженных версий статического ме­тода GetType. Принимают они в качестве аргумента String. Аргументом которым является строка должна иметь полное имя типа, а также включать его пространство имен. Если строка содержит просто имя типа, метод проверяет, определен ли тип с указанным именем в вызывающей сборке. Если это так, возвращается ссылка на соответствующий объект RuпtimeType.

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

Экземпляр класса Туре можно получить несколькими способами. Единственное, что нельзя делать — так это напрямую создавать объект Туре с помощью ключевого слова

new, потому что класс Туре является абстрактным.

Получаем разную информацию о классе с помощью методов класса Type:

Получаем информацию об именах всех методов:

Получаем информацию об именах полей класса.

Получаем список всех свойств класса:

Получаем список всех интерфейсов классов:

Получаем информацию обо всех конструкторах:

Получаем значение из полей и вносим в них запись

Класс Assembly.

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

Статические методы класса Assemdly

GetAssembly -возвращает объект Assembly

GetCallingAssembly-возвращает Assembly с кодом, вызываемым текущим методом.

GetEntryAssembly-возвращает Assembly с кодом, запустившим процесс.

GetExecutingAssembly-возвращает Assembly с кодом, исполняемым в данный момент.

Load-загружает Assembly  из текущей директории исполняемого файла.

LoadFile-загружает Assembly  из заданного каталога.

LoadFrom-загружает Assembly  в текущий AppDomain из заданного каталога.

ReflectionOnlyLoad-загружает Assembly  только для анализа, запуск сборки невозможен.

ReflectionOnlyLoadFrom-загружает Assembly  из заданного каталога только для анализа сборки, ее запуск невозможен.

Методы LoadFile и LoadFrom предоставляются для редко используемых скриптов, в которых сборка должна определяться по пути.

Чтобы получить объект Assembly для выполняемой в текущий момент сборки, следует воспользоваться методом GetExecutingAssembly.

Метод GetName возвращает объект AssemblyName, который обеспечивает доступ к отображаемому имени сборки.

Метод GetCustomAttributes используется для вывода атрибутов, примененных для сборки.

Метод GetFiles обеспечивает доступ к файлам в манифесте сборки.

При помощи класса Assembly — можно динамически загружать сборки,  обращаться к членам класса в процессе выполнения (ПОЗДНЕЕ СВЯЗЫВАНИЕ),  а так же получать  информацию о самой сборке.

Метод GetManifestResourceNames предоставляет имена всех ресурсов в манифесте сборки.

Метод GetTypes выводит все типы, содержащиеся в сборке.

Метод GetExportedTypes выводит типы, которые видимы вызывающим объектам, находящимся вне сборки.

Метод GetType может использоваться для поиска конкретного типа в сборке.

Метод CreateInstance может использоваться для поиска и создания экземпляров ряда типов в сборке.’

Перечисление BindingFlags управляет извлечением членов типа с помощью методов GetMembers и других методов, специфичных для членов типа.

Перечисление BindingFlags поддерживает флаги, то есть, принимает несколько значений.

Поздним связыванием (late binding) называется технология, которая позволяет создавать экземпляр определенного типа и вызывать его члены во время выполнения без кодирования факта его существования жестким образом на этапе компиляции. При создании приложения, в котором предусмотрено позднее связывание с типом из какой то внешней сборки, добавлять ссылку на эту сборку нет никакой причины, и потому в манифесте вызывающего кода она непосредственно не указывается.

Assembly.Load() — метод для загрузки сборки.

Метод для получения информации о всех типах в сборке.

Метод для получения информации о членах класса.

Получаем информацию о параметрах для метода TurboBoost();

Класс Activator

Класс System.Activator (определенный в сборке mscorlib.dll) играет ключевую роль в процессе позднего связывания в .NET. Его метод Createlnstance, позволят создавать экземпляр подлежащего позднему связыванию типа. Этот метод имеет несколько перегруженных версий и потому обеспечивает довольно высокую гибкость. В самой простой версии Createlnstance принимает действительный объект Туре, описывающий сущность, которая должна размещаться в памяти на лету.

Динамическая генерация кода предназначена для динамической загрузки и исполнения сборки без предварительного обращения к ней.

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

Для обеспечения динамической генерации кода, необходимо получить информацию о типах и запросить объект ConstructorInfo для конструирования нового типа. После
получения ConstructorInfo для создания требуемого объекта достаточно вызвать конструктор.

Класс Activator содержит методы для локального создания типов объектов.
Метод CreateInstance() создает экземпляр типа, определенного в сборке путем вызова конструктора, который наилучшим образом соответствует заданным аргументам.

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

Раннее связывание — все указанные выше операции выполняются во время компиляции.

Пример позднего связываения, в данном примере мы выбираем исполняемы фаил, указываем метод и работаем с ним, передавая параметры и принимая значения вычисляемые методом.

Пример исполняемого файла, с  которым мы применим позднее связывание благодаря рефлексии(отражение).

При помощи класса Activator производится позднее связывание. Метод CreateInstance() — предназначен для создания экземпляра типа во время выполнения.

Получаем экземпляр класса MethodInfo для метода MyMethod().

Массив параметров для метода

Вызов метода MyMethod.
Первый параметр — ссылка на экземпляр для которого будет вызван метод MyMethod
Второй параметр — массив аргументов метода MyMethod (в данном случае передаем массив объектов хранящий значение 3)

Еще один пример, содержащий два варианта вызова метода и его применения.

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

По аналогии мы можем использовать исполняемый фаил exe либо dll, достаточно изменить.

Класс Module

Класс Module можно использовать для извлечения или поиска типов в заданном модуле. Для сборок, изначально написанных на языке с поддержкой модулей, данный класс также поддерживает методы GetField, GetFields, GetMethod и GetMethods. К модулям данного типа поля и методы можно подключать непосредственно.

Класс Propertylnfo

Класс Propertylnfo поддерживает получение и установку отдельных свойств. В данном случае метод GetValue класса Propertylnfo вызывается для получения значения свойства Count.

Класс MemberInfo

Класс MemberInfo предназначен для исполнения произвольного кода над заданным экземпляром типа также для исполнения статического кода, связанного с определенным типом.

Генерация кода во время выполнения — техника, которая позволяет определить информацию о сборках и типах, или даже создать собственную сборку (хранимую в памяти, на диске) непосредственно в момент выполнения.

Пример: Обращаемся к полям с помощью отражения C#

Пример dll которая находится в папке с программой.

Основная программа в которой мы применяем отражение для изменения полей:

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

Пример показывающий  информацию о текущей сборке, все класс и методы.

Пример показывающий  информацию о всех сборках, подключенных dll.

Альтернативный вариант но он не работает в Unity

Создание объекта с помощью рефлексии.

Рефлексия для свойств, методов и полей

 

 

Обновлено: 08.02.2021 — 20:50

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

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

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.