Как получить список свойств класса в C#? Получение имён и типов свойств через рефлексию
Использование рефлексии для получения свойств класса
В C# для получения списка свойств класса используется пространство имён System.Reflection. Основной метод — Type.GetProperties(), который возвращает массив объектов PropertyInfo. Каждый такой объект содержит информацию об имени свойства, его типе, модификаторах доступа и многом другом.
Вот простейший пример, который выводит имена и типы всех публичных свойств класса Person:
using System;
using System.Reflection;
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public string City { get; set; }
private string secret; // поле, не свойство
}
public class Program
{
public static void Main()
{
// Получаем тип класса Person
Type personType = typeof(Person);
// Получаем все публичные свойства
PropertyInfo[] properties = personType.GetProperties();
Console.WriteLine("Свойства класса Person:");
foreach (PropertyInfo prop in properties)
{
Console.WriteLine($"- {prop.Name}: {prop.PropertyType.Name}");
}
}
}
Вывод программы:
Свойства класса Person:
- Name: String
- Age: Int32
- City: String
Подробное объяснение
- typeof(Person) — получает объект
Type, который представляет метаданные класса. - GetProperties() — возвращает только публичные свойства (public). По умолчанию он не включает статические, защищённые или приватные свойства.
- PropertyInfo — содержит свойства:
Name— имя свойства (строка).PropertyType— тип свойства (объектType).CanRead/CanWrite— проверка наличия геттера/сеттера.
Фильтрация с помощью BindingFlags
Если нужно получить не только публичные, но и, например, статические или защищённые свойства, используйте перегрузку GetProperties(BindingFlags):
// Получить все свойства (публичные и непубличные, экземплярные и статические)
PropertyInfo[] allProperties = personType.GetProperties(
BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Instance | BindingFlags.Static);
// Только статические публичные свойства
PropertyInfo[] staticProperties = personType.GetProperties(
BindingFlags.Public | BindingFlags.Static);
Получение значений свойств из объекта
Если у вас есть экземпляр класса, вы можете не только получить имена свойств, но и прочитать/записать их значения:
Person person = new Person { Name = "Анна", Age = 30, City = "Москва" };
foreach (PropertyInfo prop in personType.GetProperties())
{
object value = prop.GetValue(person); // читаем значение
Console.WriteLine($"{prop.Name} = {value}");
}
// Изменение значения
PropertyInfo ageProp = personType.GetProperty("Age");
ageProp.SetValue(person, 31);
Console.WriteLine($"Новый возраст: {person.Age}"); // 31
Важные замечания
- Рефлексия работает медленнее прямого доступа к свойствам, поэтому не используйте её в горячих циклах.
- Для сериализации/десериализации лучше использовать готовые библиотеки (Newtonsoft.Json, System.Text.Json).
- Свойства, определённые как
public string Name { get; set; }— это автоматические свойства. Рефлексия видит их как обычные свойства.
Метод GetProperties() — самый простой и часто используемый способ получить список свойств. Он идеально подходит для задач логирования, построения UI на лету или создания универсальных обработчиков данных.
Альтернативный подход: использование Expression Trees и атрибутов
Если вам нужно получить свойства не всего класса, а только определённые, помеченные кастомным атрибутом, можно комбинировать рефлексию с атрибутами. Это удобно для сериализации или валидации.
Пример: создадим атрибут [Displayable] и будем получать только свойства с ним:
[AttributeUsage(AttributeTargets.Property)]
public class DisplayableAttribute : Attribute { }
public class Person
{
[Displayable]
public string Name { get; set; }
public int Age { get; set; } // без атрибута
[Displayable]
public string City { get; set; }
}
// Получение свойств с атрибутом
var properties = typeof(Person).GetProperties()
.Where(p => p.GetCustomAttribute<DisplayableAttribute>() != null);
foreach (var prop in properties)
{
Console.WriteLine($"{prop.Name} ({prop.PropertyType.Name})");
}
// Вывод: Name (String), City (String)
Другой вариант — использовать Expression Trees для строго типизированного доступа к свойству (без магических строк):
Expression<Func<Person, string>> expression = p => p.Name;
MemberExpression member = (MemberExpression)expression.Body;
Console.WriteLine(member.Member.Name); // "Name"
Этот подход применяется в ORM (например, Entity Framework) для указания свойств в запросах. Однако для простого получения списка всех свойств класса рефлексия с GetProperties() остаётся самым прямолинейным решением.