4

I have got three classes:

public class TestA
{
    public string Str1 { get; set; }
    public string Str2 { get; set; }
    public TestB TestB { get; set; }

    public TestA()
    {
        Str1 = "string1";
        Str2 = "string2";
        TestB = new TestB();
    }
}

public class TestB
{
    public string Str3 { get; set; }
    public string Str4 { get; set; }
    public TestC ObjTestC { get; set; }
    public TestB()
    {
        Str3 = "string3";
        Str4 = "string4";
        ObjTestC = new TestC();
    }
}

public class TestC
{
    public string Str5 { get; set; }
    public TestC()
    {
        Str5 = "string5";
    }
}

Now, I have got all the PropertyInfo and created a new object:

        //Get all the properties

        var prop = typeof(TestA).GetProperties();

        for (int i = 0; i < prop.Count(); i++)
        {
            var propertyInfo = prop[i];
            if (propertyInfo.PropertyType.Namespace != "System")
            {
                if (propertyInfo.PropertyType.IsGenericType &&
                    propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(List<>))
                {
                    Type itemType = propertyInfo.PropertyType.GetGenericArguments()[0]; // use this...
                    var listObjectProperties = itemType.GetProperties();
                    prop = prop.Union(listObjectProperties).ToArray();
                }
                else
                {
                    var childProp = propertyInfo.PropertyType.GetProperties();
                    prop = prop.Union(childProp).ToArray();
                }
            }
        }


        //Create Object
        TestA testA = new TestA();

Now, what I need is to invoke the getter method of each property. I tried the following which invokes the getter of the properties of the TestA class. But, it is throwing error when trying to invoke the getter of properties in TestB and TestC:

        // Loop through all properties
        foreach (PropertyInfo propertyInfo in prop)
        {
            MethodInfo getterMethodInfo = propertyInfo.GetGetMethod();
            var obj=getterMethodInfo.Invoke(testA, null);
        }

Please help...

Thanks in advance

Daniel Schilling
  • 4,829
  • 28
  • 60
SKB
  • 159
  • 4
  • 12

1 Answers1

7

Examining this code, I expect that the prop array contains all of the properties on TestA and TestB, and doesn't touch TestC at all:

// Gets TestA's properties...
var prop = typeof(TestA).GetProperties();

// Then gets TestB's properties...
var childProp = propertyInfo.PropertyType.GetProperties();
prop = prop.Union(childProp).ToArray();

If you wanted to get properties from all three types, you should probably do it recursively. You don't want to have to modify this loop every time you change the structure of those objects a little bit.

But that's not the real problem.

The real problem is that getterMethodInfo.Invoke(testA, null) is being called against a property from TestB, but passed an instance of TestA, hence the error. Think about how you would get this value if you were not using reflection. Your existing code is essentially doing this:

var value = testA.Str3; // !!! there is no Str3 property on TestA !!!

To work correctly, your would need to do this instead:

var value = testA.TestB.Str3;

See how we're calling a chain of properties to get the desired value? First TestA.TestB, then TestB.Str3. If you need to use reflection instead, that code would need to do the same thing:

var obj = (object)testA;
obj = testBPropOnTestA.GetValue(obj, null);
var value = str3PropOnTestB.GetValue(obj, null);

So instead of storing simple instances of PropertyInfo in your collection, instead you need to store lists of PropertyInfos.

So your final "get values" loop would look more like:

foreach (var propertyChain in prop)
{
    var obj = (object)testA;
    foreach (var property in propertyChain)
    {
        obj = property.GetValue(obj, null);
        if (obj == null) {
            break;
        }
    }
    Console.WriteLine("{0} = {1}",
        string.Join(".", propertyChain.Select(x => x.Name)),
        obj);
}

I'll leave figuring out how to fix the first "gather PropertyInfos" loop to you.

Daniel Schilling
  • 4,829
  • 28
  • 60