If you need something that would work in a general case (any class hierarchy) then you could do the following:
You will need a recursive algorithm (function). The algorithm would loop over the members, adding their types to a list (if they're not already added) and then returning that list, COMBINED with the types of the members of the type just added to the list-here you make the recursive call. The terminating conditions would be:
- The type of a member is a primitive (to check this use
Type.IsPrimitive
).
- The type being reflected is defined in another assembly. You can check the defining assembly using
Type.Assembly
.
If you need something simpler, then use the technique above but just use an if statement in the loop.
Let me know if this is what you want or no and then I will post a code sample for you when I have more time.
Update: The following is a code sample showing how you can process a type and recursively get all the types contained within it. You can call it this way: List typesHere = GetTypes(myObject.GetType())
public static List<Type> GetTypes(Type t)
{
List<Type> list = new List<Type>();
if (t.IsPrimitive)
{
if (!list.Contains(t))
list.Add(t);
return list;
}
else if (!t.Assembly.Equals(System.Reflection.Assembly.GetExecutingAssembly()))
{
//if the type is defined in another assembly then we will check its
//generic parameters. This handles the List<Item> case.
var genArgs = t.GetGenericArguments();
if (genArgs != null)
foreach (Type genericArgumentType in genArgs)
{
if(!list.Contains(genericArgumentType))
list.AddRange(GetTypes(genericArgumentType));
}
return list;
}
else
{
//get types of props and gen args
var types = t.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).Select(pi => pi.PropertyType).ToList();
types.AddRange(t.GetGenericArguments());
foreach (System.Type innerType in types)
{
//get the object represented by the property to traverse the types in it.
if (!list.Contains(innerType))
list.Add(innerType);
else continue; //because the type has been already added and as thus its child types also has been already added.
var innerInnerTypes = GetTypes(innerType);
//add the types filtering duplicates
foreach (Type t1 in innerInnerTypes) //list.AddRange(innerTypes); //without filtering duplicates.
if (!list.Contains(t1))
list.Add(t1);
}
return list;
}
}
So when I ran this on the classes you posted in your original post (Item having two primitive properties like below) I got the following list:
GetTypes(typeof(List<Item>))
Count = 3
[0]: {Name = "Item" FullName = "AssemblyNameXYZ.Item"}
[1]: {Name = "String" FullName = "System.String"}
[2]: {Name = "Int32" FullName = "System.Int32"}
GetTypes(typeof(Item))
Count = 2
[0]: {Name = "String" FullName = "System.String"}
[1]: {Name = "Int32" FullName = "System.Int32"}
Reflection.GetTypes(typeof(RootClass))
Count = 5
[0]: {Name = "List`1" FullName = "System.Collections.Generic.List`1[[AssemblyNameXYZ.Item, AssemblyNameXYZ, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"}
[1]: {Name = "Item" FullName = "AssemblyNameXYZ.Item"}
[2]: {Name = "String" FullName = "System.String"}
[3]: {Name = "Int32" FullName = "System.Int32"}
[4]: {Name = "SubClass" FullName = "AssemblyNameXYZ.SubClass"}
I didn't make comprehensive tests but this should at least point you to the right direction. Fun question. I have fun answering.