I wanna have all properties of an object which have primitive type, and if the object has a relation to another class , I wanna have the primitive properties of this another
I am bored at work waiting for a build, have fun with your homework ;)
namespace Scratchpad
{
public static class TypeExtractor
{
public static IEnumerable<Type> ExtractTypes(this Type owner, HashSet<Type> visited = null)
{
if (visited == null)
visited = new HashSet<Type>();
if (visited.Contains(owner))
return new Type[0];
visited.Add(owner);
switch (Type.GetTypeCode(owner))
{
case TypeCode.Object:
break;
case TypeCode.Empty:
return new Type[0];
default:
return new[] {owner};
}
return
owner.GetMembers(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance |
BindingFlags.Static |
BindingFlags.FlattenHierarchy)
.SelectMany(x => x.ExtractTypes(visited)).Union(new[] {owner}).Distinct();
}
public static IEnumerable<Type> ExtractTypes(this MemberInfo member, HashSet<Type> visited)
{
switch (member.MemberType)
{
case MemberTypes.Property:
return ((PropertyInfo) member).PropertyType.ExtractTypes(visited);
break;
case MemberTypes.Field:
return ((FieldInfo) member).FieldType.ExtractTypes(visited);
default:
return new Type[0];
}
}
}
public class A
{
public string Name { get; set; }
public B B { get; set; }
}
public class B
{
public string Category { get; set; }
public A A { get; set; }
}
internal class Program
{
private static void Main(string[] args)
{
var q = typeof (A).ExtractTypes();
foreach (var type in q)
{
Console.Out.WriteLine(type.Name);
}
}
}
}
You could keep a track of visited types to avoid recursion:
public class A
{
public string Name { get; set; }
public B B { get; set; }
}
public class B
{
public string Category { get; set; }
public A A { get; set; }
}
class Program
{
static void Main()
{
var result = Visit(typeof(A));
foreach (var item in result)
{
Console.WriteLine(item.Name);
}
}
public static IEnumerable<PropertyInfo> Visit(Type t)
{
var visitedTypes = new HashSet<Type>();
var result = new List<PropertyInfo>();
InternalVisit(t, visitedTypes, result);
return result;
}
private void InternalVisit(Type t, HashSet<Type> visitedTypes, IList<PropertyInfo> result)
{
if (visitedTypes.Contains(t))
{
return;
}
if (!IsPrimitive(t))
{
visitedTypes.Add(t);
foreach (var property in t.GetProperties())
{
if (IsPrimitive(property.PropertyType))
{
result.Add(property);
}
InternalVisit(property.PropertyType, visitedTypes, result);
}
}
}
private static bool IsPrimitive(Type t)
{
// TODO: put any type here that you consider as primitive as I didn't
// quite understand what your definition of primitive type is
return new[] {
typeof(string),
typeof(char),
typeof(byte),
typeof(sbyte),
typeof(ushort),
typeof(short),
typeof(uint),
typeof(int),
typeof(ulong),
typeof(long),
typeof(float),
typeof(double),
typeof(decimal),
typeof(DateTime),
}.Contains(t);
}
}
I would made as follows:
void Traverse(Type type, ISet<Type> marks, ICollection<PropertyInfo> result)
{
if (marks.Contains(type)) return; else marks.Add(type);
foreach (var propertyInfo in type.GetProperties())
if (propertyInfo.PropertyType.IsPrimitive) result.Add(propertyInfo);
else Traverse(propertyInfo.PropertyType, marks, result);
}
and
var props = new List<PropertyInfo>();
Traverse(yourRootType, new HashSet<Type>(), props);
You need to keep track of types you've already checked.
public static List<PropertyInfo> ProcessType(Type type)
{
return ProcessType(type, new List<Type>());
}
public static List<PropertyInfo> ProcessType(Type type, List<Type> processedTypes)
{
// Keep track of results
var result = new List<PropertyInfo>();
// Iterate properties of the type
foreach (var property in type.GetProperties())
{
var propertyType = property.PropertyType;
// If the property has a primitive type
if (propertyType.IsPrimitive)
{
// add it to the results
result.Add(property);
}
// If the property has a non-primitive type
// and it has not been processed yet
else if (!processedTypes.Contains(propertyType))
{
// Mark the property's type as already processed
processedTypes.Add(propertyType);
// Recursively processproperties of the property's type
result.AddRange(ProcessType(propertyType, processedTypes));
}
}
return result;
}