Free cookie consent management tool by TermsFeed Policy Generator

Changeset 6380 for trunk/sources


Ignore:
Timestamp:
06/07/11 16:55:38 (13 years ago)
Author:
mkommend
Message:

#1522: Replaced recursive object graph traversing with a linear solution using a stack to avoid stack overflows.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/sources/HeuristicLab.Common/3.3/ObjectExtensions.cs

    r6205 r6380  
    2424using System.Collections.Generic;
    2525using System.Collections.Specialized;
     26using System.Linq;
    2627using System.Reflection;
    27 using System.Threading;
    2828
    2929namespace HeuristicLab.Common {
    3030  public static class ObjectExtensions {
    3131    public static IEnumerable<object> GetObjectGraphObjects(this object obj) {
     32      if (obj == null) return Enumerable.Empty<object>();
     33
    3234      var objects = new HashSet<object>();
    33       obj.CollectObjectGraphObjects(objects);
     35      var stack = new Stack<object>();
     36
     37      stack.Push(obj);
     38      while (stack.Count > 0) {
     39        object current = stack.Pop();
     40        Type type = obj.GetType();
     41        objects.Add(current);
     42
     43        foreach (object o in GetChildObjects(current)) {
     44          if (o != null && !objects.Contains(o) && !ExcludeType(o.GetType()))
     45            stack.Push(o);
     46        }
     47      }
     48
    3449      return objects;
    3550    }
     
    4560    /// compared to traverse their internal data structures.
    4661    /// </summary>
    47     private static void CollectObjectGraphObjects(this object obj, HashSet<object> objects) {
    48       if (obj == null || objects.Contains(obj)) return;
     62    private static bool ExcludeType(Type type) {
     63      return type.IsPrimitive ||
     64             type == typeof(string) ||
     65             type == typeof(decimal) ||
     66             typeof(Delegate).IsAssignableFrom(type) ||
     67             typeof(Pointer).IsAssignableFrom(type) ||
     68             (type.HasElementType && ExcludeType(type.GetElementType()));
     69    }
     70    private static IEnumerable<object> GetChildObjects(object obj) {
    4971      Type type = obj.GetType();
    50       if (ExcludeType(type)) return;
    51       if (type.HasElementType && ExcludeType(type.GetElementType())) return;
    5272
    53       objects.Add(obj);
    54 
    55       if (type.IsSubclassOfRawGeneric(typeof(ThreadLocal<>))) return; // avoid stack overflow when the field `ConcurrentStack<int> s_availableIndices` too grows large
    56      
    57       // performance critical to handle dictionaries, hashsets and hashtables in a special way
    58       if (type.IsSubclassOfRawGeneric(typeof(Dictionary<,>)) ||
    59           type.IsSubclassOfRawGeneric(typeof(SortedDictionary<,>)) ||
    60           type.IsSubclassOfRawGeneric(typeof(SortedList<,>)) ||
    61           obj is SortedList ||
    62           obj is OrderedDictionary ||
    63           obj is ListDictionary ||
    64           obj is Hashtable) {       
     73      if (type.IsSubclassOfRawGeneric(typeof(Dictionary<,>)) ||
     74         type.IsSubclassOfRawGeneric(typeof(SortedDictionary<,>)) ||
     75         type.IsSubclassOfRawGeneric(typeof(SortedList<,>)) ||
     76         obj is SortedList ||
     77         obj is OrderedDictionary ||
     78         obj is ListDictionary ||
     79         obj is Hashtable) {
    6580        var dictionary = obj as IDictionary;
    6681        foreach (object value in dictionary.Keys)
    67           CollectObjectGraphObjects(value, objects);
     82          yield return value;
    6883        foreach (object value in dictionary.Values)
    69           CollectObjectGraphObjects(value, objects);
    70         return;
     84          yield return value;
    7185      } else if (type.IsArray || type.IsSubclassOfRawGeneric(typeof(HashSet<>))) {
    7286        var enumerable = obj as IEnumerable;
    7387        foreach (var value in enumerable)
    74           CollectObjectGraphObjects(value, objects);
    75         return;
     88          yield return value;
     89      } else {
     90        foreach (FieldInfo f in type.GetAllFields()) {
     91          yield return f.GetValue(obj);
     92        }
    7693      }
    77 
    78       foreach (FieldInfo f in type.GetAllFields()) {
    79         f.GetValue(obj).CollectObjectGraphObjects(objects);
    80       }
    81     }
    82 
    83     private static bool ExcludeType(Type type) {
    84       return type.IsPrimitive ||
    85              type == typeof(string) ||
    86              type == typeof(decimal) ||
    87              typeof(Delegate).IsAssignableFrom(type) ||
    88              typeof(Pointer).IsAssignableFrom(type);
    8994    }
    9095  }
Note: See TracChangeset for help on using the changeset viewer.