Pingpong
Pingpong

Reputation: 8009

Reading properties of hierarchical classes generically using reflection in C#

I have a set of classes that are generated via xsd.exe based on *.xsd files. Each set of classes generated for each set of *.xsd files are almost the same, except that there are a few properties different in each class. For example, in both set 1 and set 2, Shape class might have different property.

I want to use a method to read the value of specified properties (UPDATE) of all classes in one set at a time (Update). There could be many levels of class. The method (e.g. GetProperty method) should only know about its parameter type, and the string representation of all properties. The method only read property.

Is there a better way of doing this:

    internal class DynPropertyTest
    {
        public static void Set1Test()
        {
            Shape shape = new Shape()
            {
                Name = "Shape",
                Shape2 = new Shape2()
                {
                   Name = "Shape2",
                   Shape3 = new Shape3() { Name = "Shape3" }
                }
            };

            GetProperty(shape);
        }

        public static void Set2Test() {
            ...
           }

UPDATE I would like to know an alternative way to achieve the similar function to the the method below

 //Should store all properties value in a collection, rather than display it
           //And somehow store/know the type of the property.
        public static void GetProperty(ShapeBase shape)
        {
            //shape.Name             


                Console.WriteLine(shape.GetType().GetProperty("Name").GetValue(shape, null));

            //Shape.Shape2
            object shape2 = shape.GetType().GetProperty("Shape2").GetValue(shape, null);
            Console.WriteLine(shape2);

            //Shape.Shape2.Name
            object shape2Name = shape.GetType().GetProperty("Shape2").PropertyType.GetProperty("Name")
                .GetValue(shape2, null);
            Console.WriteLine(shape2Name);

            //shape.shape2.shape3
            object shape3 = shape2.GetType().GetProperty("Shape3").GetValue(shape2, null);
            Console.WriteLine(shape3);

            //shape.shape2.shape3.Name
            object shape3Name = shape2.GetType().GetProperty("Shape3").PropertyType.GetProperty("Name")
                .GetValue(shape3, null);
            Console.WriteLine(shape3Name);
        }
    }

    abstract class ShapeBase { }

   //Example only. 
    namespace Set1
    {
        class Shape : ShapeBase
        {
            public string Name { get; set; }
            public Shape2 Shape2 { get; set; }
        }

        class Shape2
        {
            public string Name { get; set; }
            public Shape3 Shape3 { get; set; }
        }

        class Shape3
        {
            public string Name { get; set; }

        }
    }

    namespace Set2
    {
        class Shape : ShapeBase{}
       ...
    }

Upvotes: 0

Views: 2389

Answers (1)

competent_tech
competent_tech

Reputation: 44941

This is how we implement this functionality (this is for getting a String value for dynamic SQL, but you should be able to apply it to your situation:

    public static string GetFieldValueForSQL(object oRecord, string sName)
    {
        PropertyInfo theProperty = null;
        FieldInfo theField = null;
        System.Type oType = null;

        try
        {
            oType = oRecord.GetType();

            // See if the column is a property in the record
            theProperty = oType.GetProperty(sName, BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.Public, null, null, new Type[0], null);
            if (theProperty == null)
            {
                theField = oType.GetField(sName, BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.Public);
                if (theField != null)
                {
                    return theField.GetValue(oRecord).ToString();
                }
            }
            else
            {
                return theProperty.GetValue(oRecord, null).ToString();
            }
        }
        catch (Exception theException)
        {
            // Do something with the exception
            return string.empty;
        }
    }

Update

To process all of the properties, you can use code similar to this (note that this does not take into account IEnumerable implementors, but that should be fairly straightforward):

    public static void GetAllProperties(object oRecord)
    {
        System.Type oType = null;
        try
        {
            oType = oRecord.GetType();

            PropertyInfo[] cProperties;

            cProperties = oType.GetProperties(BindingFlags.Instance | BindingFlags.Public);

            foreach (PropertyInfo theProperty in cProperties)
            {
                if (theProperty.PropertyType.IsClass)
                {
                    GetAllProperties(theProperty.GetValue(oRecord, null));
                }
                else
                {
                    // use theProperty.GetValue(oRecord, null).ToString();
                }
            }
        }
        catch (Exception theException)
        {
            // Do something with the exception
        }
    }

Upvotes: 2

Related Questions