2

I'm trying to loop through a class and it's child classes to get the values passed with it.

Here's my class:

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

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

Here's my code so far

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>();
    }
}

Two questions:

  1. What do I pass to GetProperties, to pass the child class, for it to then loop through it's properties if it's a class?
  2. How do I get the value from the property item if it isn't a class?

Hopefully this all makes sense. If not, don't hesitate to ask and I'll try and clarify.

Thanks

david.s
  • 11,283
  • 6
  • 50
  • 82
Richard Whitehouse
  • 679
  • 3
  • 14
  • 28
  • What do you mean by "get the value from the property item if it isn't a class"? Do you want to retrieve the _value assigned_ to that property? So retrieve the _instance_ of `ChildClass1` that was assigned to that property? EDIT: Or do you mean if the property is a value-type (struct)? If so, doesn't matter, it will work anyway. – Chris Sinclair May 01 '13 at 11:34
  • What exactly do you mean by "value from the property"? You don't pass any instance of MainClass to GetProperties, so where should the value come from? – Heinzi May 01 '13 at 11:35
  • Apologies. Slightly confused things slightly and missed half my question. ;-) My main aim is to pass an instance of MainClass, e.g. with values in, then loop through it, and it's child classes and get the values set against any values. Hopefully that clears things up! Apologies! – Richard Whitehouse May 01 '13 at 12:19

4 Answers4

6

You can easily rewrite it to be recursive without generics:

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);
    }
}

Not sure on your second question "how do I get the value from the property item if it isn't a class" (I'll edit/update when we figure that out)

Chris Sinclair
  • 22,858
  • 3
  • 52
  • 93
  • 1
    +1, just what I was about to write. NB: The generic version won't work for recursion since generic type arguments must be known *at compile time* (which works for `GetProperties` but not for `GetProperties`). – Heinzi May 01 '13 at 11:37
  • @Heinzi Well, you _could_ leverage reflection to still use only the generic version... but that would be silly. – Chris Sinclair May 01 '13 at 11:38
5

Chris already answered the first part of your question, so I won't repeat that. For the second part, as soon as you have an instance of MainClass, you can just use the (aptly named) PropertyInfo.GetValue method:

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

(If you use .NET 4.5, you can omit the second (null) parameter. Earlier versions require it, though.)

In the end, your code could look like this (I shamelessly copied and extended Chris' version) (untested):

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);
        }
    }
}

Note that this code will fail if any of your objects use indexed properties (C# indexers or properties with parameters in VB). In that case, GetValue would need to be provided with the appropriate index or parameter.

Heinzi
  • 167,459
  • 57
  • 363
  • 519
0

Regarding your second question, if you want to get the value from the property item, you must provide the object of the Type. Heinzi has explained how to get the value by the property. I provide a shell version without generics.

 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));
        }
    }
usharei
  • 31
  • 1
0
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;

    }

Try this which iterates over properties only if it is class

ZafarYousafi
  • 8,640
  • 5
  • 33
  • 39