views:

3049

answers:

3

Hello,

I’m working on a reflection project, and now I’m stuck. If I have an object of “myclass” that can hold a List does anyone know how to get the type as in the code below if the property myclass.SomList is empty?

List<myclass>  myList  =  dataGenerator.getMyClasses();
lbxObjects.ItemsSource = myList; 
lbxObjects.SelectionChanged += lbxObjects_SelectionChanged;

private void lbxObjects_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            Reflect();
        }
Private void Reflect()
{
foreach (PropertyInfo pi in lbxObjects.SelectedItem.GetType().GetProperties())
{
      switch (pi.PropertyType.Name.ToLower())
      {
       case "list`1":
           {           
            // This works if the List<T> contains one or more elements.
            Type tTemp = GetGenericType(pi.GetValue(lbxObjects.SelectedItem, null));

            // but how is it possible to get the Type if the value is null? 
            // I need to be able to create a new object of the type the generic list expect. 
            // Type type = pi.getType?? // how to get the Type of the class inside List<T>?
             break;
           }
      }
}
}
private Type GetGenericType(object obj)
        {
            if (obj != null)
            {
                Type t = obj.GetType();
                if (t.IsGenericType)
                {
                    Type[] at = t.GetGenericArguments();
                    t = at.First<Type>();
                } return t;
            }
            else
            {
                return null;
            }
        }
+30  A: 
Type type = pi.PropertyType.PropertyType;
if(type.IsGenericType && type.GetGenericTypeDefinition()
        == typeof(List<>))
{
    Type itemType = type.GetGenericArguments()[0]; // use this...
}


More generally, to support any IList<T>, you need to check the interfaces:

foreach (Type interfaceType in type.GetInterfaces())
{
    if (interfaceType.IsGenericType &&
        interfaceType.GetGenericTypeDefinition()
        == typeof(IList<>))
    {
        Type itemType = type.GetGenericArguments()[0];
        // do something...
        break;
    }
}
Marc Gravell
+1 Nicely done!
Andrew Hare
+1 for really nice work!
Cobus Kruger
shouldn't it be Type itemType = interfaceType.GetGenericArguments()[0];
Muxa
+1  A: 

Marc's answer is the approach I use for this, but for simplicity (and a friendlier API?) you can define a property in the collection base class if you have one such as:

public abstract class CollectionBase<T> : IList<T>
{
   ...

   public Type ElementType
   {
      get
      {
         return typeof(T);
      }
   }
}

I have found this approach useful, and is easy to understand for any newcomers to generics.

GaryJL
I wanted to use this approach but then i realized i will have to have the list instance in order to determine element type, which i will not always have.
Muxa
A: 

Thanks!

my problem came from the object that I was Reflecting on... tok a look at the class and the property list were never instanciated.

but thanx anyway.