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)) { return; } var typeCode = Type.GetTypeCode(value.Type); 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.DBNull: visitor.VisitScalar(new BetterObjectDescriptor(null, typeof(object), typeof(object)), context); break; case TypeCode.Empty: throw new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "TypeCode.{0} is not supported.", typeCode)); default: 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(new BetterObjectDescriptor(value.Value, underlyingType, value.Type, value.ScalarStyle), visitor, currentDepth, context); } else { TraverseObject(value, visitor, currentDepth, context); } break; } }