public static void WalkObjectGraph(object currentNode, bool walkCollections, WalkGraphAction action, Stack <object> objectStack, Func <PropertyInfo, bool> performActionOnProperty, Func <Type, bool> interestingTypeFunction = null) { if (currentNode == null) { return; } if (null == objectStack) { // Maintain a stack of objects in the hierarchy so we don't get stuck processing loops in the graph objectStack = new Stack <object>(); } else if (objectStack.Contains(currentNode)) { // We've already walked this object, so we have a circular reference, let's not overflow the stack. return; } objectStack.Push(currentNode); interestingTypeFunction = interestingTypeFunction ?? (t => true); // Act on the current object if (interestingTypeFunction(currentNode.GetType())) { action(null, currentNode, objectStack); } // Walk down into the object graph for properties that have objects var objectProperties = currentNode.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (var prop in objectProperties) { // Skip read or write only properties if (!prop.CanRead || !prop.CanWrite) { continue; } // Check to see if we should perform the action() on this property if (performActionOnProperty(prop) && interestingTypeFunction(prop.GetType())) { action(prop, currentNode, objectStack); } // Check to see if this property holds an object we can walk into object value; try { value = prop.GetValue(currentNode); } catch (Exception) { continue; } if (null != value) { if (walkCollections && value is IEnumerable && !(value is string)) { foreach (var obj in (IEnumerable)value) { WalkObjectGraph(obj, walkCollections, action, objectStack, performActionOnProperty, interestingTypeFunction); } } else if (!(value is IEnumerable)) { WalkObjectGraph(value, walkCollections, action, objectStack, performActionOnProperty, interestingTypeFunction); } } } objectStack.Pop(); }
internal static void WalkObjectGraph <TAttribute>(object source, bool intoCollections, WalkGraphAction action, Stack <object> parentObjectStack = null) where TAttribute : Attribute { WalkObjectGraph(source, intoCollections, action, parentObjectStack, p => p.GetCustomAttributes <TAttribute>(true).Any(), null); }