Created
          March 17, 2014 11:33 
        
      - 
      
- 
        Save feanz/d8dc15fedec7ba4a0c25 to your computer and use it in GitHub Desktop. 
    Walk Object Graph
  
        
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | public static class ReflectionExtensions | |
| { | |
| /// <summary> | |
| /// Walks an object graph performing a function for any object in the graph that implements T or any collection that implements T | |
| /// </summary> | |
| /// <typeparam name="T"></typeparam> | |
| /// <param name="toWalk">Item to walk from</param> | |
| /// <param name="snippetForObject">Function for each item of type T</param> | |
| /// <param name="snippetForCollection">Function for each IEnumerable of type T</param> | |
| /// <param name="exemptProperties">Properties to exempt</param> | |
| public static void WalkObjectGraph<T>(this T toWalk, Func<T, bool> snippetForObject, | |
| Action<IList> snippetForCollection = null, | |
| params string[] exemptProperties) where T : class | |
| { | |
| var visited = new List<T>(); | |
| Action<T> walk = null; | |
| var exemptions = new List<string>(); | |
| if (exemptProperties != null) | |
| exemptions = exemptProperties.ToList(); | |
| walk = o => | |
| { | |
| if (o != null && !visited.Contains(o)) | |
| { | |
| visited.Add(o); | |
| var exitWalk = snippetForObject.Invoke(o); | |
| if (!exitWalk) | |
| { | |
| var properties = o.GetBrowsableProperties(); | |
| foreach (var property in properties) | |
| { | |
| if (!exemptions.Contains(property.Name)) | |
| { | |
| var propertyType = property.PropertyType; | |
| if (typeof(T).IsAssignableFrom(propertyType)) | |
| { | |
| var subProperty = (T)property.GetValue(o, null); | |
| walk(subProperty); | |
| } | |
| var implementsIEnumerable = propertyType.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>)); | |
| if (implementsIEnumerable) | |
| { | |
| var genericArgument = propertyType.GetGenericArguments()[0]; | |
| if (typeof(T).IsAssignableFrom(genericArgument)) | |
| { | |
| var col = property.GetValue(o, null) as IList; | |
| if (col != null) | |
| { | |
| if (snippetForCollection != null) | |
| snippetForCollection.Invoke(col); | |
| foreach (var item in col) | |
| { | |
| walk((T)item); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }; | |
| walk(toWalk); | |
| } | |
| /// <summary> | |
| /// Get all public reference properties or collection types (implement IEnumerable) which are not decorated with IEnumerable | |
| /// </summary> | |
| /// <param name="item"></param> | |
| /// <returns></returns> | |
| public static IEnumerable<PropertyInfo> GetBrowsableProperties(this object item) | |
| { | |
| return item.GetType() | |
| .GetProperties() | |
| .Where(info => !Attribute.IsDefined(info, typeof(NoneNavigateable)) | |
| && (info.PropertyType.IsClass || typeof(IEnumerable).IsAssignableFrom(info.PropertyType)) | |
| && info.PropertyType != typeof(string)); | |
| } | |
| } | 
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment