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;
            }
        }