-1

I understand how to use Reflection to get the property name and value of a given class. But what if that property is an array containing 1 or more of another class?

var person = new
{
    Name = "John",
    Characteristic = new[]
    {
        new Characteristic {Name = "Age", Value = "31"},
        new Characteristic {Name = "Height", Value = "6'1""},
    }
};

var properties = person.GetType().GetProperties();
foreach (var property in properties)
{
    Console.WriteLine(property.Name);
    Console.WriteLine(property.GetValue(person));
    if (property.PropertyType.IsArray)
    {
        // Need to get info here! (See below)
    }
}

Basically, I need to get that the particular property is an array of Characteristic and then the properties Name and Value and then the subsequent values of those properties. Thanks very much!

**edit: this is what I tried and I couldn't get the values I needed...this code was in place of the comment above

foreach (var prop in property.GetType().GetProperties())
{
    Console.WriteLine(prop.Name);
    Console.WriteLine(prop.GetValue(property));
}
kroe761
  • 3,296
  • 9
  • 52
  • 81
  • An array is just a different type of object, so you can retrieve it using [GetValue](https://msdn.microsoft.com/en-us/library/b05d59ty(v=vs.110).aspx) just like any other type. What part of the problem is giving you trouble? – John Wu May 07 '18 at 20:28
  • I added the code I tried. Not sure what's wrong here. – kroe761 May 07 '18 at 20:33

3 Answers3

0

You still utilize GetValue() but for array properties it returns an array cast to object so you need to cast it back to Array explicitly

if (property.PropertyType.IsArray)
{
    foreach (var item in (Array)property.GetValue(person))
        Console.WriteLine(item);
}

If you need to access the item's properties as well, repeat the same property scammin routine to the item objects:

if (property.PropertyType.IsArray)
{
    foreach (var item in (Array)property.GetValue(person))
    {
        var subProperties = item.GetType().GetProperties();
        foreach (var subProperty in subProperties)
        {
            Console.WriteLine(subProperty.Name);
            Console.WriteLine(subProperty.GetValue(item));
        }
    }
}

And more generic version processing arbitrary levels of nested array properties:

TraverseProps(person);
// ..................................................
static void TraverseProps(object obj, int level = 0)
{
    string indent = new string(' ', level * 2);
    if (obj == null)
    {
        Console.WriteLine(indent + "<NULL>");
        return;
    }
    var properties = obj.GetType().GetProperties();
    foreach (var property in properties)
    {
        var value = property.GetValue(obj);
        Console.Write(indent + property.Name + ": ");
        if (property.PropertyType.IsArray)
        {
            Console.WriteLine(indent + "[");
            int i = 0;
            foreach (var item in (Array)value)
            {
                Console.WriteLine(indent + "item " + i + ":");
                TraverseProps(item, level + 1);
                i++;
            }
            Console.WriteLine(indent + "]");
        }
        else
        {
            Console.WriteLine(value);
        }
    }
}

N.B. This function is prone to infinite recursion in case of reference loops in the object tree.

Dmitry Egorov
  • 9,542
  • 3
  • 22
  • 40
0

After you retrieve the array instance (using GetValue as normal), you can use LINQ's Cast() method to convert it to an IEnumerable of the appropriate type, like this:

var characteristics = person.GetType().GetProperty("Characteristic", BindingFlags.Instance | BindingFlags.Public).GetValue(person, null) as System.Array;
foreach (var c in characteristics.Cast<Characteristic>())
{
    Console.WriteLine("{0} = {1}", c.Name, c.Value);
}

If you don't have early-bound access to the Characteristic class, you can also use pure reflection:

var characteristics = person.GetType().GetProperty("Characteristic", BindingFlags.Instance | BindingFlags.Public).GetValue(person, null) as System.Array;
foreach (var o in characteristics)
{
    var name = o.GetType().GetProperty("Name", BindingFlags.Public | BindingFlags.Instance).GetValue(o, null);
    var val  = o.GetType().GetProperty("Value", BindingFlags.Public | BindingFlags.Instance).GetValue(o, null);
    Console.WriteLine("{0} = {1}", name, val);
}

The output in both cases is:

Age = 31
Height = 6'1"

Link to DotNetFiddle demo

John Wu
  • 50,556
  • 8
  • 44
  • 80
0

Here is what i came up with that works. This would have been in the if statement above:

if (property.PropertyType.IsArray)
{
    foreach (var item in (Array) property.GetValue(person))
    {
        var props = item.GetType().GetProperties();
        foreach (var prop in props)
        {
            Console.WriteLine(prop.Name);
            Console.WriteLine(prop.GetValue(item));
        }
    }
}
kroe761
  • 3,296
  • 9
  • 52
  • 81