Атрибуты и рефлексия
Часть раздела Объектно-ориентированное программирование путешествия по C# на Coddy. Урок 44 из 70.
Атрибуты — это теги метаданных, которые прикрепляются к элементам кода, таким как class, methods или свойства. Они не изменяют непосредственно выполнение кода, но предоставляют информацию, которую можно прочитать во время выполнения. Рефлексия — это механизм, который считывает эти метаданные.
Вы применяете attribute, помещая его в квадратные скобки над целевым элементом:
[Obsolete("Use NewMethod instead")]
public void OldMethod() { }
[Serializable]
public class Person
{
public string Name { get; set; }
}Вы можете создавать пользовательские атрибуты, наследуя их от Attribute:
public class AuthorAttribute : Attribute
{
public string Name { get; }
public AuthorAttribute(string name) => Name = name;
}
[Author("John")]
public class Calculator { }Рефлексия позволяет проверять типы и читать атрибуты во время выполнения, используя пространство имён System.Reflection:
Type type = typeof(Calculator);
var attr = type.GetCustomAttribute<AuthorAttribute>();
Console.WriteLine(attr.Name); // JohnВы также можете обнаруживать методы и свойства, а также динамически вызывать их:
MethodInfo[] methods = type.GetMethods();
foreach (var method in methods)
Console.WriteLine(method.Name);Атрибуты и рефлексия лежат в основе многих фреймворков: библиотеки сериализации используют их для управления выводом JSON, фреймворки тестирования — для обнаружения методов тестов, а контейнеры внедрения зависимостей — для автоматического связывания сервисов.
Задание
ЛегкоДавайте создадим систему обнаружения плагинов, которая использует custom attributes и reflection, чтобы автоматически находить и описывать class, отмеченные как плагины. Это похоже на то, как реальные фреймворки обнаруживают компоненты, test methods или API endpoints во время выполнения.
Вы организуете код в трёх файлах:
PluginAttribute.cs: создайте custom attribute с именемPluginAttributeв namespacePluginSystem. Ваш attribute должен:- Inherit от
Attribute - Have два свойства только для чтения:
Name(string) иVersion(string) - Принимать оба значения через constructor
- Inherit от
Plugins.cs: создайте несколько plugin class в namespacePluginSystem. Некоторые из них должны быть помечены вашимPluginAttribute, а один — нет:ImageProcessor— отмечен с помощью[Plugin("Image Processor", "1.0")]DataExporter— отмечен с помощью[Plugin("Data Exporter", "2.5")]HelperUtility— НЕ отмечен никаким attribute (это просто обычный class)
Program.cs: в основном файле используйте reflection, чтобы обнаружить все class, у которых естьPluginAttribute. Для каждого обнаруженного plugin выведите его информацию. Вам потребуется:- Получить все types из current assembly
- Check каждый type на наличие
PluginAttribute - Извлечь и отобразить свойства attribute
NameиVersion
Используйте System.Reflection, чтобы проверять types и получать custom attributes. Метод GetCustomAttribute<T>() возвращает null, если attribute отсутствует, поэтому его можно использовать для фильтрации class, которые действительно являются plugin.
Выводите каждый обнаруженный plugin в следующем формате, по одному в строке:
Plugin: {Name} (v{Version})Плагины должны выводиться в следующем порядке: сначала ImageProcessor, затем DataExporter. Class HelperUtility не должен появляться в выводе, поскольку у него отсутствует attribute.
Ожидаемый вывод:
Plugin: Image Processor (v1.0)
Plugin: Data Exporter (v2.5)Это задание демонстрирует, как фреймворки используют attributes в качестве маркеров и reflection для их обнаружения — тот же метод лежит в основе контейнеров dependency injection, библиотек сериализации и testing frameworks!
Попробуйте сами
using System;
using System.Reflection;
using PluginSystem;
class Program
{
public static void Main(string[] args)
{
// TODO: Получить все типы из текущей сборки
// Подсказка: Используйте Assembly.GetExecutingAssembly().GetTypes()
// TODO: Пройтись по каждому типу и проверить, есть ли у него PluginAttribute
// Подсказка: Используйте type.GetCustomAttribute<PluginAttribute>()
// TODO: Если атрибут существует, выведите информацию о плагине в формате:
// Plugin: {Name} (v{Version})
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыПространства имен и директивыВведение в классы и объектыКлючевое слово 'this'Методы и параметрыПоля и свойстваКонструкторыИнициализаторы объектовИтоги — Простой калькулятор4Наследование
Основы синтаксиса наследования (:)Ключевое слово 'base'Ключевые слова Virtual и OverrideЗапечатанные классыБазовый класс 'object'Итоги — Иерархия сотрудников7Продвинутые возможности
Перегрузка операторовИндексаторы (this[])Переопределение ToString()Методы расширенияПовторение — Пользовательский список10Паттерны проектирования. Часть 1
Введение в паттерны проектированияПотокобезопасный SingletonПаттерн FactoryПаттерн Observer (События)Паттерн Strategy13Финальные испытания
Платформа для онлайн-обученияКомпонент игрового персонажаСервис аренды транспорта2Свойства и статические члены
Автоматически реализуемые свойстваСвойства только для чтения и записиСтатические поля и методыСтатические классыЧлены в виде выражений5Полиморфизм и интерфейсы
Полиморфизм: компиляция vs выполнениеИнтерфейс vs абстрактный классМножественные интерфейсыЯвные интерфейсыUpcasting и DowncastingИтоги: Калькулятор фигур8Продвинутые концепции ООП
Композиция вместо наследованияGenerics (классы и методы)Делегаты и событияАтрибуты и рефлексияIDisposable и оператор usingОсновы Dependency Injection11Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн Компоновщик3Архитектура классов
Экземплярные и статические данныеКлючевые слова 'readonly' и 'const'Опорные поляПовторение — Менеджер банковских счетов6Инкапсуляция
Модификаторы доступаСвойства для инкапсуляцииРеализация скрытия данныхПаттерны неизменяемостиИтоги — Записи студентов9Переменное количество аргументов
Ключевое слово 'params'Необязательные параметрыИменованные аргументыПерегрузка методовПотренируйтесь самостоятельно: Онлайн-компилятор C#