Find all instances of Type in an object graph

Viewed 126

Lets say i have the following object graph

Parent : BaseEntity
  string1 SimpleString
  Middle Middle
  List<Child> Children (3)

Middle : BaseEntity
  string NormalStr
  int NiceInt
  RandomClass Ignore

 Child : BaseEntity
   string ChildString
   Parent Parent
  

In this example i want a way to give my Parent as input and get back a flat list {Parent, Middle, Child1, Child2, Child3}. It should work for any type of object graph.

Im trying to get there with reflection and recursion. The problem i run into is the cyclic reference between Parent and Child and i end up in an infinite loop.

How do i prevent this? I cant seem to get any "already seen" mechanism to work.

This is what i got so far. It works without the collection part, but that part is pretty important...

    public void TraverseThroughProperties(object myObject)
    {
        foreach (var prop in myObject.GetType().GetProperties())
        {
            var instance = prop.GetValue(myObject);
            if (instance is BaseEntity myBase)
                TraverseThroughProperties(instance);


            if (instance is ICollection collection)
            {
                foreach (var item in collection.OfType<BaseEntity>())
                    TraverseThroughProperties(item);
            }

            // Do something with myObject + prop
        }
    }
1 Answers

If i understand the question correctly, I guess the easiest way would be keep a HashSet of the types you have visited.

public static void TraverseThroughProperties(object myObject, HashSet<Type> hashset = null)
{
   hashset ??= new HashSet<Type>();
   if (hashset.Contains(myObject.GetType()))
      return;
   hashset.Add(myObject.GetType());
   ...

Note : this might not be optimal as it will reject the same types. The other way is to keep a tuple of the parent child types visited. however once again this might filter more than expected.

public static void TraverseThroughProperties(object myObject, object parent, HashSet<(Type,Type)> hashset = null)
{
   hashset ??= new HashSet<(Type,Type)>();
   ...

Another way, is to hash the actual reference. Which would keep track of references, or once again, keep track of parent child references

public static void TraverseThroughProperties(object myObject, HashSet<object> hashset = null)
{
   hashset ??= new HashSet<object>();
   if (hashset.Contains(myObject))
      return;
   hashset.Add(myObject);

Though still might not be what you are looking for and filter too much. This then becomes a conceptual problem, and you may need to rethink what you are doing and why.

Related