Использование отражения для получения свойства из поля

#c#

Вопрос:

У меня есть эти занятия:

 public class Foo
{
    public Bar bar;
}

public class Bar
{
    public List<int> Something { get; set; }
    public string Else { get; set; }
}
 

У меня много таких занятий Foo . Все они содержат ровно одно поле. Это поле, Bar в моем примере, каждый раз будет объектом другого типа, оно не обязательно должно иметь тип Bar . Каким бы объектом это ни было ( Bar или иным образом), это поле всегда будет объектом, имеющим два свойства, Something и Else .

Моя задача: учитывая любой объект, подобный Foo (с одним полем, содержащим два свойства), получите значение двух свойств. Учитывая этот метод:

 public void DoStuff(object myObject)
{
    var asdf = myObject.GetType().GetFields().First();
}
 

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

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

Комментарии:

1. И я предполагаю, что тип Something всегда a List<int> и Else всегда a string ?

2. @Sweeper Это правильно. Я уточню вопрос.

Ответ №1:

Используя этот код, вы можете получить PropertyInfo s для Something и для Else свойства:

 Foo myObject = new Foo { bar = new Bar() };

// the FieldInfo for Foo.bar
var barField = myObject.GetType().GetFields().First();

// the Bar instance, i.e. myObject.bar
var barValue = barField.GetValue(myObject);

var somethingProperty = barField.FieldType.GetProperty("Something", BindingFlags.Instance | BindingFlags.Public);
var elseProperty = barField.FieldType.GetProperty("Else", BindingFlags.Instance | BindingFlags.Public);
 

как отметил PsiHamster, затем вы можете использовать GetValue и SetValue для извлечения и установки значений somethingProperty и elseProperty подобных этому:

 // get the value
var somethingValue = somethingProperty.GetValue(barValue);

// set the value
somethingProperty.SetValue(barValue, new List<int>());
 

Комментарии:

1. На самом деле свойство поддерживает GetValue() метод, поэтому вам не нужно самостоятельно вызывать методы

2. Спасибо, это блестяще работает. Теперь мне не нужно писать более 1000 строк конфигурации автомата. Огромное спасибо.

3. @yesman Рад слышать, что это помогает. Если вы действительно используете это в производстве, пожалуйста, обязательно подумайте о кэшировании FieldInfo и PropertyInfo s, чтобы вы не вызывали GetFields() и GetProperty() для каждого объекта.

Ответ №2:

 //Get Bar FieldInfo
var barFieldInfo = myObject.GetType().GetFields().First();

// Get all public instance properties info
var barProps = barFieldInfo.FieldType.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);

// Get Something and Else properties info
var smthPropInfo = barProps.First(prop => prop.Name == nameof(Bar.Something));
var elsePropInfo = barProps.First(prop => prop.Name == nameof(Bar.Else));

// Get values
var bar = barFieldInfo.GetValue(myObject);
var smth = smthPropInfo.GetValue(bar);
var else = elsePropInfo.GetValue(bar);