Skip to content

Instantly share code, notes, and snippets.

@BrutalSimplicity
Last active June 22, 2016 01:03
Show Gist options
  • Save BrutalSimplicity/d6647b9727a585f36bd1f6f21fbfdc38 to your computer and use it in GitHub Desktop.
Save BrutalSimplicity/d6647b9727a585f36bd1f6f21fbfdc38 to your computer and use it in GitHub Desktop.
Enumerates nearly all public properties in an object graph.
/// <summary>
/// Enumerates "all" public properties in an object graph. All is used loosely as this
/// may miss some older public property types that aren't enumerable (.Net v1 maybe).
/// CAUTION: Do not use on object graphs with cycles, as it will cause infinite reucrsion.
/// Additionally, this can be a VERY expensive call if used on a large object graph.
/// Ensure your use case can sustain the time-cost implications.
/// </summary>
/// <param name="obj">Object to traverse</param>
/// <returns>Enumerable set of properties</returns>
private static IEnumerable<Tuple<object, PropertyInfo>> GetWiredProperties(object obj)
{
// Avoid recursive calls by using a stack and tuple to save frames
Stack<Tuple<object, PropertyInfo[]>> stack = new Stack<Tuple<object, PropertyInfo[]>>();
stack.Push(new Tuple<object, PropertyInfo[]>(obj, obj.GetType().GetProperties()));
while (stack.Count > 0)
{
var frame = stack.Pop();
foreach (var prop in frame.Item2)
{
if (frame.Item1 != null)
{
yield return new Tuple<object, PropertyInfo>(frame.Item1, prop);
if (!prop.PropertyType.IsValueType)
{
// If the type is a collection or array, push each item onto
// the stack so we can traverse its object graph
if (prop.PropertyType.IsArray ||
(prop.PropertyType.GetInterface(typeof(ICollection<>).FullName) != null) ||
typeof(ICollection).IsAssignableFrom(prop.PropertyType))
{
var temp = prop.GetValue(frame.Item1, null);
var collection = temp as IEnumerable;
if (collection != null)
{
foreach (var indexedObject in collection)
stack.Push(new Tuple<object, PropertyInfo[]>(indexedObject, indexedObject.GetType().GetProperties()));
}
}
else
stack.Push(new Tuple<object, PropertyInfo[]>(prop.GetValue(frame.Item1, null), prop.PropertyType.GetProperties()));
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment