Содержание
При разработке программ в C# бывает необходимым определить имеется ли у экземпляра класса определенное свойство, проверить или записать его значение. Для выполнения этих и других операций мы можем воспользоваться классом из System.Reflection PropertyInfo. Этот класс предоставляет подробную информацию о свойстве класса или объекта.
Объект исследования
Допишем наш класс Person, используемый в прошлой статье, следующим образом:
class Account
{
public string Login { get; set; }
public string Password { get; set; }
}
class Person
{
public Person()
{
Account = new Account();
}
public Person(string name, string family, byte age):this()
{
Name = name;
Family = family;
Age = age;
}
public string Name { get; set; }
public string Family { get; set; }
private byte age;
public byte Age
{
get
{
return age;
}
set
{ if (value > 100)
throw new Exception("Возраст человека не может быть больше 100 лет");
else
age = value;
}
}
public Account Account { get; private set; }
}
Как можно увидеть, у нашего класса определено свойство Account, которое представляет собой т.н. вложенный тип.
Как найти определенное свойство класса в C#
Чтобы найти определенное свойство класса можно воспользоваться методом GetProperty(), например, следующим образом:
Person user = new Person("Вася", "Пупкин", 18);
user.Account.Login = "Uasya";
user.Account.Password = "password";
Type type = user.GetType();
PropertyInfo property = type.GetProperty("AcCoUnt", BindingFlags.IgnoreCase | BindingFlags.Instance| BindingFlags.Public);
if (property != null)
Console.WriteLine("Свойство найдено");
else
Console.WriteLine("Свойство не найдено");
Здесь следует обратить внимание на выставленные флаги BindingFlags. Используя связку BindingFlags.IgnoreCase | BindingFlags.Instance| BindingFlags.Public, мы пробуем найти публичное свойство, игнорируя регистр букв в имени. Поэтому результатом выполнения этого кода будет следующая строка:
Если свойство обнаружено, то, используя методы и свойства класса PropertyInfo мы можем его детально исследовать:
Person user = new Person("Вася", "Пупкин", 18);
user.Account.Login = "Uasya";
user.Account.Password = "password";
Type type = user.GetType();
PropertyInfo property = type.GetProperty("AcCoUnt", BindingFlags.IgnoreCase | BindingFlags.Instance| BindingFlags.Public);
if (property != null)
{
Console.WriteLine("Свойство найдено");
Console.WriteLine($"Тип свойства: {property.PropertyType}");
Console.WriteLine($"Доступно для чтения: {property.CanRead}");
Console.WriteLine($"Доступно для записи: {property.CanWrite}");
bool isClass = property.PropertyType.IsClass;
Console.WriteLine($"Свойство является классом: {isClass}");
if (isClass)
{
Console.WriteLine($"Перечисляем свойства класса {property.PropertyType.Name}");
foreach (PropertyInfo info in property.PropertyType.GetProperties())
{
Console.WriteLine($" {info.PropertyType.Name} {info.Name}");
}
}
}
else
Console.WriteLine("Свойство не найдено");
Результат работы:
Тип свойства: Reflection.Account
Доступно для чтения: True
Доступно для записи: True
Свойство является классом: True
Перечисляем свойства класса Account
String Login
String Password
Получив информацию о конкретном свойстве мы можем получить или записать его значение для указанного экземпляра (объекта).
Как получить значение свойства объекта в C#
Попробуем прочитать значение найденного свойства. Для этого воспользуемся методом GetValue() у PropertyInfo. Допишем наш пример следующим образом:
[...]
if (isClass)
{
Console.WriteLine($"Перечисляем свойства класса {property.PropertyType.Name}");
foreach (PropertyInfo info in property.PropertyType.GetProperties())
{
Console.WriteLine($" {info.PropertyType.Name} {info.Name} Значение свойства: {info.GetValue(property.GetValue(user))}");
}
}
[...]
Результат выполнения программы:
Тип свойства: Reflection.Account
Доступно для чтения: True
Доступно для записи: True
Свойство является классом: True
Перечисляем свойства класса Account
String Login Значение свойства: Uasya
String Password Значение свойства: password
Здесь стоит обратить внимание на то, как мы получили значение свойства. Для того, чтобы получить значение свойства мы должны обязательно передать в метод экземпляр (объект) исследуемого класса. В нашем случае, это объект с именем user. Таким образом, вначале мы использовали метод GetValue() для того, чтобы получить объект Account из объекта user и только затем мы передали значение свойства Account в метод GetValue(), чтобы прочитать значение свойств Login и Password.
Конечно, в реальном проекте мы можем столкнуться с ситуацией, когда свойство какого-либо класса само является классом, а этот класс содержит в себе свойство, которое также является классом и т.д., то есть вложенность объектов в исследуемом экземпляре может быть самая разная. В этом случае код приложения (если использовать способ приведенный выше) станет весьма и весьма запутанным. Но,можно воспользоваться следующим приемом, чтобы получить информацию о свойстве:
private static PropertyInfo GetProperty(object t, string PropertName)
{
if (t.GetType().GetProperties().Count(p => p.Name == PropertName.Split('.')[0]) == 0)
throw new ArgumentNullException(string.Format("Property {0}, is not exists in object {1}", PropertName, t.ToString()));
if (PropertName.Split('.').Length == 1)
return t.GetType().GetProperty(PropertName);
else
return GetProperty(t.GetType().GetProperty(PropertName.Split('.')[0]).GetValue(t, null), PropertName.Split('.')[1]);
}
В приведенном методе необходимо указать ссылку на экземпляр класса (объект) и имя свойства, которое необходимо найти, при этом вложенность свойства определяется точками, например:
PropertyInfo property = GetProperty(user, "Account.Login");
В данном случае, мы пробуем получить информацию о свойстве Login, которое относится к объекту Account, который, в свою очередь является свойством объекта user.
Как записать значение свойства объекта в C#
Для записи значения свойства нам необходимо воспользоваться методом SetValue(). Например:
Person user = new Person("Вася", "Пупкин", 18);
user.Account.Login = "Uasya";
user.Account.Password = "password";
Type type = user.GetType();
PropertyInfo property = type.GetProperty("Name");
if (property != null)
{
Console.WriteLine($"Старое значение свойства {property.GetValue(user)}");
property.SetValue(user, "Петя");
Console.WriteLine($"Новое значение свойства {property.GetValue(user)}");
}
Итого
Для работы со свойствами классов и объектов C# используется класс PropertyInfo. Используя экземпляры этого класса мы можем получить детальную информацию о свойстве, а также прочитать или записать его значение для определенного экземпляра класса, используя, соответственно, методы GetValue() и SetValue().