Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Рефлексия в C#
Рефлексия (Reflection) — это один из самых мощных, но и одновременно самых опасных инструментов в .NET. Я видел код, где неправильное использование рефлексии затухала производительность приложения в 100 раз. Но когда она используется правильно, это чудо техники.
Определение
Рефлексия — это способность программы во время выполнения изучать информацию о типах, методах, свойствах, конструкторах и других элементах сборки. Это позволяет динамически создавать объекты, вызывать методы и изменять значения, которые вы знаете только во время выполнения.
Основной концепт
using System.Reflection;
var person = new Person { Name = "Ivan", Age = 30 };
// Получаем информацию о типе
Type personType = person.GetType(); // Type = Person
// Читаем информацию о типе
Console.WriteLine(personType.Name); // "Person"
Console.WriteLine(personType.Namespace); // "MyApp"
Console.WriteLine(personType.BaseType.Name); // "Object"
Основные возможности рефлексии
1. Получение информации о типах
var type = typeof(Person);
// Все публичные свойства
var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var prop in properties)
{
Console.WriteLine($"{prop.Name}: {prop.PropertyType}");
// Output:
// Name: System.String
// Age: System.Int32
}
// Все методы
var methods = type.GetMethods();
// Все конструкторы
var constructors = type.GetConstructors();
2. Динамическое создание объектов
// Создание объекта через рефлексию
var type = Type.GetType("MyApp.Person");
object person = Activator.CreateInstance(type); // new Person()
// С параметрами конструктора
object person = Activator.CreateInstance(type, "Ivan", 30);
3. Динамическое чтение и запись свойств
var person = new Person { Name = "Ivan", Age = 30 };
var type = person.GetType();
// Чтение свойства
var nameProperty = type.GetProperty("Name");
var name = nameProperty.GetValue(person); // "Ivan"
// Запись свойства
nameProperty.SetValue(person, "Pavel");
Console.WriteLine(person.Name); // "Pavel"
4. Динамическое вызывание методов
var person = new Person();
var type = person.GetType();
// Получаем метод
var method = type.GetMethod("GetInfo");
// Вызываем его
object result = method.Invoke(person, null); // Вызов GetInfo()
Console.WriteLine(result); // Результат метода
5. Проверка наличия атрибутов
[Serializable]
public class Person
{
[Required]
public string Name { get; set; }
}
// Проверка атрибутов класса
var type = typeof(Person);
bool isSerializable = type.IsDefined(typeof(SerializableAttribute));
// Проверка атрибутов свойства
var nameProperty = type.GetProperty("Name");
bool isRequired = nameProperty.IsDefined(typeof(RequiredAttribute));
Реальные примеры использования
Пример 1: Сериализация JSON
public static string SerializeToJson(object obj)
{
var type = obj.GetType();
var properties = type.GetProperties();
var pairs = new List<string>();
foreach (var prop in properties)
{
var value = prop.GetValue(obj);
var json = value is string ? $"\"{value}\"" : value;
pairs.Add($"\"{prop.Name}\":{json}");
}
return "{" + string.Join(",", pairs) + "}";
}
var person = new Person { Name = "Ivan", Age = 30 };
var json = SerializeToJson(person);
// Output: {"Name":"Ivan","Age":30}
Пример 2: Автоматическое маппирование объектов
public static TTarget Map<TSource, TTarget>(TSource source)
where TTarget : new()
{
var target = new TTarget();
var sourceType = source.GetType();
var targetType = typeof(TTarget);
// Копируем все свойства с одинаковым именем
var properties = sourceType.GetProperties();
foreach (var sourceProp in properties)
{
var targetProp = targetType.GetProperty(sourceProp.Name);
if (targetProp != null && targetProp.CanWrite)
{
var value = sourceProp.GetValue(source);
targetProp.SetValue(target, value);
}
}
return target;
}
var personDto = new PersonDTO { Name = "Ivan", Age = 30 };
var person = Map<PersonDTO, Person>(personDto);
Пример 3: Dependency Injection контейнер
public class SimpleContainer
{
private Dictionary<Type, Type> _registrations = new();
public void Register<TInterface, TImplementation>()
where TImplementation : TInterface
{
_registrations[typeof(TInterface)] = typeof(TImplementation);
}
public T Resolve<T>()
{
var interfaceType = typeof(T);
var implementationType = _registrations[interfaceType];
// Получаем конструктор
var constructor = implementationType.GetConstructors().First();
// Рекурсивно резолвим зависимости
var parameters = constructor.GetParameters();
var parameterInstances = parameters.Select(p => Resolve(p.ParameterType)).ToArray();
// Создаём объект
return (T)Activator.CreateInstance(implementationType, parameterInstances);
}
private object Resolve(Type type)
{
// Похожая логика для не-generic типов
...
}
}
Производительность рефлексии
Рефлексия медленнее обычного кода в 100-1000 раз. Вот сравнение:
var person = new Person { Name = "Ivan" };
var type = person.GetType();
var property = type.GetProperty("Name");
// Обычное чтение: ~0.01 микросекунд
var name1 = person.Name;
// Рефлексия: ~1-10 микросекунд
var name2 = property.GetValue(person);
Оптимизация рефлексии
1. Кешируй Type и PropertyInfo
// ❌ Медленно — ищет тип каждый раз
foreach (var person in people)
{
var type = person.GetType();
var prop = type.GetProperty("Name");
var name = prop.GetValue(person);
}
// ✅ Быстро — кешируем
var type = typeof(Person);
var property = type.GetProperty("Name");
foreach (var person in people)
{
var name = property.GetValue(person);
}
2. Используй Expression Trees для частого использования
public class FastPropertyGetter<T>
{
private Func<T, object> _getter;
public FastPropertyGetter(string propertyName)
{
var property = typeof(T).GetProperty(propertyName);
var parameter = Expression.Parameter(typeof(T));
var memberAccess = Expression.Property(parameter, property);
var cast = Expression.Convert(memberAccess, typeof(object));
var lambda = Expression.Lambda<Func<T, object>>(cast, parameter);
_getter = lambda.Compile(); // Компилируем в IL
}
public object GetValue(T instance) => _getter(instance); // Близко к нормальной скорости
}
3. Используй Source Generators (C# 9+)
Инстеад of рефлексии, let compiler generate code:
[GenerateMapper]
public partial class PersonMapper { }
// Compiler generates fast mapping code automatically
Когда использовать рефлексию
✅ Используй рефлексию для:
- Сериализации/десериализации
- Фреймворков (DI, ORM, MVC)
- Плагинов и расширяемости
- Валидации и маппинга
- Когда тип известен только во время выполнения
❌ НЕ используй в:
- Горячих loop'ах с высокой частотой
- Обработке микросекундных данных
- Когда есть альтернатива (generics, delegate'ы)
Выводы для интервью
- Рефлексия позволяет изучать и манипулировать типами во время выполнения
- Это мощный инструмент для фреймворков, но медленнее обычного кода в 100+ раз
- Всегда кеши Type и PropertyInfo если используешь рефлексию в loop'ах
- Source Generators — современная альтернатива рефлексии
- Используй только когда действительно нужна динамичность