views:

443

answers:

2

Hi All,

I am trying to to use reflection to achieve the following:

I need a method where i pass in an object and this method will recursively instantiate the object with child objects and set the properties with default values. I need the entire object instantiated going as many levels as needed.

this method needs to be able to handle an object with a multiple properties that will be generic lists of other objects.

Here is my sample code (I am getting a parameter count mismatch exception when i get an object containing a list:

        private void SetPropertyValues(object obj)
    {
        System.Reflection.PropertyInfo[] properties = obj.GetType().GetProperties();

        foreach (System.Reflection.PropertyInfo property in properties)
        {
            if (property.PropertyType.IsClass && property.PropertyType != typeof(string) && property.PropertyType.FullName.Contains("BusinessObjects"))
            {
                Type propType = property.PropertyType;

                var subObject = Activator.CreateInstance(propType);
                SetPropertyValues(subObject);
                property.SetValue(obj, subObject, null);
            }
            else if (property.PropertyType == typeof(string))
            {
                property.SetValue(obj, property.Name, null);
            }
            else if (property.PropertyType == typeof(DateTime))
            {
                property.SetValue(obj, DateTime.Today, null);
            }
            else if (property.PropertyType == typeof(int))
            {
                property.SetValue(obj, 0, null);
            }
            else if (property.PropertyType == typeof(decimal))
            {
                property.SetValue(obj, 0, null);
            }
        }
    }

Thanks

A: 

This is a tricky one :)

When you pass your initializer an object containing a generic list of some "BusinessObjects" type as a property, then this property will pass your

if (property.PropertyType.IsClass && property.PropertyType != typeof(string) && property.PropertyType.FullName.Contains("BusinessObjects"))

expression, because the instantiated generic type will have a name like this:

System.Collections.Generic.List`1[[ConsoleApplication92.XXXBusinessObjects, ConsoleApplication92, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]

This results in the initializer method being called with the List itself as a parameter. The list will have an indexer named Item of type SomeBusinessObjects. This will too pass the above condition so you'll try to initialize it too. It results is something like this:

obj.ListProperty.Item = new SomeBusinessObject();

whereas an indexer could only be used in an initialization like this

obj.ListProperty[0] = new SomeBusinessObject();

This shows, that indeed, your are missing a parameter.

What you gonna do about this is up to you :)

kicsit
See my answer. :)
Nayan
A: 

You can filter out by checking for property.PropertyType.IsGeneric which is true for generic containers. If you need, also check for property.PropertyType.IsArray.

Moreover, you may also want to avoid non-generic containers. In that case, test for object to be of interface types of such containers. Eg - IList.

bool isList(object data)
{
    System.Collections.IList list = data as System.Collections.IList;
    return list != null;
}

...
if (isList(obj)) {
    //do stuff that take special care of object which is a List
    //It will be true for generic type lists too!
}
Nayan
OR you could just use the language's "is" operator (which exists for this exact purpose), and avoid an unnecessary method call and equality comparison.
Ian Kemp