Перебор классов и дочерних классов для извлечения свойств и значений в C#

Я пытаюсь пройти через класс и его дочерние классы, чтобы получить переданные с ним значения.

Вот мой класс:

public class MainClass
{
    bool IncludeAdvanced { get; set; }

    public ChildClass1 ChildClass1 { get; set; }
    public ChildClass2 ChildClass2 { get; set; }
}

Вот мой код до сих пор

GetProperties<MainClass>();

private void GetProperties<T>()
{
    Type classType = typeof(T);
    foreach (PropertyInfo property in classType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
    {
        WriteToLog(property.Name + ": " + property.PropertyType + ": " + property.MemberType);
        GetProperties<property>();
    }
}

Два вопроса:

  1. Что мне передать в GetProperties, чтобы передать дочерний класс, чтобы он затем перебирал его свойства, если это класс?
  2. Как получить значение из элемента свойства, если это не класс?

Надеюсь, все это имеет смысл. Если нет, не стесняйтесь спрашивать, и я постараюсь уточнить.

Спасибо


person Richard Whitehouse    schedule 01.05.2013    source источник
comment
Что вы подразумеваете под получением значения из элемента свойства, если это не класс? Вы хотите получить значение, присвоенное этому свойству? Итак, получить экземпляр ChildClass1, который был назначен этому свойству? РЕДАКТИРОВАТЬ: Или вы имеете в виду, является ли свойство типом значения (структурой)? Если да, то не беда, все равно будет работать.   -  person Chris Sinclair    schedule 01.05.2013
comment
Что именно вы подразумеваете под ценностью от свойства? Вы не передаете ни одного экземпляра MainClass в GetProperties, так откуда же взять значение?   -  person Heinzi    schedule 01.05.2013
comment
Извинения. Немного напутал и пропустил половину моего вопроса. ;-) Моя главная цель - передать экземпляр MainClass, например. со значениями, затем прокрутите его и его дочерние классы и получите значения, установленные против любых значений. Надеюсь, это прояснит ситуацию! Извинения!   -  person Richard Whitehouse    schedule 01.05.2013


Ответы (4)


Крис уже ответил на первую часть вашего вопроса, поэтому я не буду повторяться. Во второй части, как только у вас будет экземпляр MainClass, вы можете просто использовать (подходящее имя) метод PropertyInfo.GetValue:

object value = property.GetValue(myInstance, null);

(Если вы используете .NET 4.5, вы можете опустить второй (null) параметр Однако более ранние версии требуют этого.)

В конце концов, ваш код может выглядеть так (я беззастенчиво скопировал и расширил версию Криса) (не проверено):

private void GetProperties<T>(T instance)
{
    GetProperties(typeof(T), instance);
}

private void GetProperties(Type classType, object instance)
{
    foreach (PropertyInfo property in classType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
    {
        WriteToLog(property.Name + ": " + property.PropertyType + ": " + property.MemberType);

        object value = property.GetValue(instance, null);
        if (value != null) {
            WriteToLog(value.ToString());
            GetProperties(property.PropertyType, value);
        }
    }
}

Обратите внимание, что этот код завершится ошибкой, если какой-либо из ваших объектов использует индексированные свойства (C# индексаторы или свойства с параметрами в VB). В этом случае GetValue должен быть снабжен соответствующим индексом или параметром.

person Heinzi    schedule 01.05.2013

Вы можете легко переписать его, чтобы он был рекурсивным без дженериков:

private void GetProperties<T>()
{
    GetProperties(typeof(T));
}

private void GetProperties(Type classType)
{
    foreach (PropertyInfo property in classType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
    {
        WriteToLog(property.Name + ": " + property.PropertyType + ": " + property.MemberType);
        GetProperties(property.PropertyType);
    }
}

Не уверен в вашем втором вопросе «как мне получить значение из элемента свойства, если это не класс» (я отредактирую/обновлю, когда мы это выясним)

person Chris Sinclair    schedule 01.05.2013
comment
+1, как раз то, что я собирался написать. NB: универсальная версия не будет работать для рекурсии, поскольку аргументы универсального типа должны быть известны во время компиляции (что работает для GetProperties<MainClass>, но не для GetProperties<somethingDeterminedAtRuntime>). - person Heinzi; 01.05.2013
comment
@Heinzi Ну, вы могли использовать отражение, чтобы по-прежнему использовать только общую версию ... но это было бы глупо. - person Chris Sinclair; 01.05.2013

Что касается вашего второго вопроса, если вы хотите получить значение из элемента свойства, вы должны предоставить объект типа. Хайнци объяснил, как получить значение по свойству. Я предоставляю версию оболочки без дженериков.

 private static void ResolveTypeAndValue(object obj)
    {
        var type = obj.GetType();
        foreach (var p in type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance))
        {
            if (p.PropertyType.IsClass && p.PropertyType != typeof(string))
            {
                var currentObj = p.GetValue(obj);
                ResolveTypeAndValue(currentObj);
            }
            else
                Console.WriteLine("The value of {0} property is {1}", p.Name, p.GetValue(obj));
        }
    }
person usharei    schedule 01.05.2013

public IEnumerable<PropertyInfo> GetProperties(Type type)
    {
        //Just to avoid the string
        if (type == typeof(String)) return new PropertyInfo[] { };
        var properties = type.GetProperties().ToList();
        foreach (var p in properties.ToList())
        {
            if (p.PropertyType.IsClass)
                properties.AddRange(GetProperties(p.PropertyType));
            else if (p.PropertyType.IsGenericType)
            {
                foreach (var g in p.PropertyType.GetGenericArguments())
                {
                    if (g.IsClass)
                        properties.AddRange(GetProperties(g));
                }
            }
        }
        return properties;

    }

Попробуйте это, которое перебирает свойства, только если это класс

person ZafarYousafi    schedule 01.05.2013