protected virtual void Traverse <TContext>(IObjectDescriptor value, IObjectGraphVisitor <TContext> visitor, int currentDepth, TContext context) { if (++currentDepth > maxRecursion) { throw new InvalidOperationException("Too much recursion when traversing the object graph"); } if (visitor.Enter(value, context)) { TypeCode typeCode = value.Type.GetTypeCode(); switch (typeCode) { case TypeCode.Boolean: case TypeCode.Char: case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: case TypeCode.DateTime: case TypeCode.String: visitor.VisitScalar(value, context); break; case TypeCode.Empty: throw new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "TypeCode.{0} is not supported.", typeCode)); default: if (value.IsDbNull()) { visitor.VisitScalar((IObjectDescriptor) new ObjectDescriptor(null, typeof(object), typeof(object)), context); } if (value.Value == null || value.Type == typeof(TimeSpan)) { visitor.VisitScalar(value, context); } else { Type underlyingType = Nullable.GetUnderlyingType(value.Type); if (underlyingType != null) { Traverse(new ObjectDescriptor(value.Value, underlyingType, value.Type, value.ScalarStyle), visitor, currentDepth, context); } else { TraverseObject(value, visitor, currentDepth, context); } } break; } } }
protected virtual void Traverse <TContext>(object name, IObjectDescriptor value, IObjectGraphVisitor <TContext> visitor, TContext context, Stack <ObjectPathSegment> path) { if (path.Count >= maxRecursion) { var message = new StringBuilder(); message.AppendLine("Too much recursion when traversing the object graph."); message.AppendLine("The path to reach this recursion was:"); var lines = new Stack <KeyValuePair <string, string> >(path.Count); var maxNameLength = 0; foreach (var segment in path) { var segmentName = TypeConverter.ChangeType <string>(segment.name); maxNameLength = Math.Max(maxNameLength, segmentName.Length); lines.Push(new KeyValuePair <string, string>(segmentName, segment.value.Type.FullName)); } foreach (var line in lines) { message .Append(" -> ") .Append(line.Key.PadRight(maxNameLength)) .Append(" [") .Append(line.Value) .AppendLine("]"); } throw new MaximumRecursionLevelReachedException(message.ToString()); } if (!visitor.Enter(value, context)) { return; } path.Push(new ObjectPathSegment(name, value)); try { var typeCode = value.Type.GetTypeCode(); switch (typeCode) { case TypeCode.Boolean: case TypeCode.Byte: case TypeCode.Int16: case TypeCode.Int32: case TypeCode.Int64: case TypeCode.SByte: case TypeCode.UInt16: case TypeCode.UInt32: case TypeCode.UInt64: case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: case TypeCode.String: case TypeCode.Char: case TypeCode.DateTime: visitor.VisitScalar(value, context); break; case TypeCode.Empty: throw new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "TypeCode.{0} is not supported.", typeCode)); default: if (value.IsDbNull()) { visitor.VisitScalar(new ObjectDescriptor(null, typeof(object), typeof(object)), context); } if (value.Value == null || value.Type == typeof(TimeSpan)) { visitor.VisitScalar(value, context); break; } var underlyingType = Nullable.GetUnderlyingType(value.Type); if (underlyingType != null) { // This is a nullable type, recursively handle it with its underlying type. // Note that if it contains null, the condition above already took care of it Traverse("Value", new ObjectDescriptor(value.Value, underlyingType, value.Type, value.ScalarStyle), visitor, context, path); } else { TraverseObject(value, visitor, context, path); } break; } } finally { path.Pop(); } }