/// <summary>
        /// Parses a JSON snippet of an array value.
        /// </summary>
        /// <typeparam name="T">The type of the object to parse the array items into.</typeparam>
        /// <param name="json">The string containing the JSON snippet, begining and ending with square brackets.</param>
        /// <param name="typeResolver">A class to help resolving dynamic or unknown types.</param>
        /// <returns>The parsed array.</returns>
        public static T[] LoadArray <T>(string json, JsonTypeResolver typeResolver)
        {
            int i = 0;

            IList list = ReadArray(json, ref i, typeof(T[]), typeResolver ?? JsonTypeResolver.FromAssemblyMappings <T>(), true);

            T[] array = new T[list.Count];

            list.CopyTo(array, 0);
            return(array);
        }
        private static List <object> ReadArray(string s, ref int i, Type expectedValueType, JsonTypeResolver typeResolver, bool standalone = false)
        {
            global::System.Diagnostics.Debug.Assert(s != null);
            global::System.Diagnostics.Debug.Assert(i >= 0 && i < s.Length);
            global::System.Diagnostics.Debug.Assert(s[i] == '[');

            List <object> values = new List <object>();
            Type          expectedArrayValueType = null;

            if (expectedValueType != null)
            {
                Type[] listTypes;

                if (expectedValueType.HasElementType)
                {
                    expectedArrayValueType = expectedValueType.GetElementType();
                }

                else if (expectedValueType.Implements(typeof(IList <>), out listTypes))
                {
                    expectedArrayValueType = listTypes[0].GenericTypeArguments[0];
                }
            }

            ++i;
            EnsureNotEndOfString(s, i);
            SkipWhitespace(s, ref i);

            if (s[i] != ']')
            {
                while (true)
                {
                    object arrayValue = ReadValue(s, ref i, null, expectedArrayValueType, typeResolver);
                    values.Add(arrayValue);

                    SkipWhitespace(s, ref i);
                    if (s[i] == ']')
                    {
                        break;
                    }

                    ReadNextMemberSeparator(s, ref i);
                    SkipWhitespace(s, ref i);
                }
            }

            ++i;

            //if (!standalone)
            //    EnsureNotEndOfString(s, i);

            return(values);
        }
        private static object ReadValue(string s, ref int i, object value, Type expectedValueType, JsonTypeResolver typeResolver)
        {
            JsonValueType jsonType = ReadValueType(s, ref i);

            switch (jsonType)
            {
            case JsonValueType.String:
                value = ReadString(s, ref i);
                break;

            case JsonValueType.Number:
                value = ReadNumber(s, ref i);
                break;

            case JsonValueType.Object:
                if (value == null)
                {
                    if (expectedValueType != null)
                    {
                        ConstructorInfo memberCtor = expectedValueType.GetConstructor(new Type[0]);

                        if (memberCtor == null)
                        {
                            throw new FormatException("A type with parameter-less constructor is required at position " + i + ". If not available, supply an instance as the member's value.");
                        }

                        value = memberCtor.Invoke(null);
                    }
                    else
                    {
                        value = new Dictionary <string, object>();
                    }
                }

                LoadFromJson(value, s, ref i, typeResolver);
                break;

            case JsonValueType.Array:
                List <object> arrayValues = ReadArray(s, ref i, expectedValueType, typeResolver);

                if (expectedValueType != null && expectedValueType.IsArray)
                {
                    Array array = Array.CreateInstance(expectedValueType.GetElementType(), arrayValues.Count);

                    object[] genericArray = arrayValues.ToArray();
                    genericArray.CopyTo(array, 0);
                    value = array;
                }
                else if (value is IList)
                {
                    IList valueList = (IList)value;
                    try
                    {
                        valueList.Clear();
                        foreach (object arrayValue in arrayValues)
                        {
                            valueList.Add(arrayValue);
                        }
                    }
                    catch (Exception e)
                    {
                        global::System.Diagnostics.Debug.WriteLine("Array values could not be loaded at position {0}. Skipping. ({1})", i, e.Message);
                    }
                }
                else if (expectedValueType == null || expectedValueType.IsAssignableFrom(typeof(IList)))
                {
                    value = arrayValues;
                }
                else if (expectedValueType.Implements <IList>())
                {
                    ConstructorInfo memberCtor = expectedValueType.GetConstructor(new Type[0]);

                    if (memberCtor == null)
                    {
                        throw new FormatException("A type with parameter-less constructor is required at position " + i + ". If not available, supply an instance as the member's value.");
                    }

                    IList valueList = (IList)memberCtor.Invoke(null);
                    try
                    {
                        valueList.Clear();
                        foreach (object arrayValue in arrayValues)
                        {
                            valueList.Add(arrayValue);
                        }
                    }
                    catch (Exception e)
                    {
                        global::System.Diagnostics.Debug.WriteLine("Array values could not be loaded at position {0}. Skipping. ({1})", i, e.Message);
                    }

                    value = valueList;
                }
                else
                {
                    throw new NotSupportedException("'" + expectedValueType + "' is not a supported type for loading array values.");
                }
                break;

            case JsonValueType.True:
                value = true;
                break;

            case JsonValueType.False:
                value = false;
                break;

            case JsonValueType.Null:
                value = null;
                break;

            default:
                throw new NotSupportedException("Unsupported JSON type.");
            }
            return(value);
        }
        /// <summary>
        /// Parses a JSON snippet of a value.
        /// </summary>
        /// <typeparam name="T">The type of the object to parse.</typeparam>
        /// <param name="json">The string containing the JSON snippet.</param>
        /// <param name="typeResolver">A class to help resolving dynamic or unknown types.</param>
        /// <returns>The parsed value.</returns>
        public static T LoadObject <T>(string json, JsonTypeResolver typeResolver) where T : new()
        {
            int i = 0;

            return((T)ReadValue(json, ref i, null, typeof(T), typeResolver ?? JsonTypeResolver.FromAssemblyMappings <T>()));
        }
        private static void LoadFromJson <T>(T target, string json, ref int i, JsonTypeResolver typeResolver)
        {
            if (target == null)
            {
                throw new ArgumentNullException("target");
            }

            if (json == null)
            {
                throw new ArgumentNullException("json");
            }

            Type targetType = typeof(T);

            if (target != null)
            {
                targetType = target.GetType();
            }

            IDictionary <string, PropertyInfo> memberResolver   = GetAttributeMemberResolver(targetType);
            List <ResolverPending>             resolverPendings = new List <ResolverPending>();

            SkipWhitespace(json, ref i);
            ReadObjectStart(json, ref i);

            do
            {
                SkipWhitespace(json, ref i);

                if (json[i] == '}')
                {
                    break;
                }

                string memberName = ReadMemberName(json, ref i);

                SkipWhitespace(json, ref i);
                ReadMemberValueSeparator(json, ref i);
                SkipWhitespace(json, ref i);

                if (target is IDictionary)
                {
                    IDictionary targetTable = (IDictionary)target;

                    Type expectedTableValueType = null;
                    if (targetTable is TypeInKeyHashtable)
                    {
                        expectedTableValueType = typeResolver.ResolveType(memberName);
                    }

                    targetTable.Add(memberName, ReadValue(json, ref i, null, expectedTableValueType, typeResolver));
                    goto nextMember;
                }

                PropertyInfo memberProperty = null;
                memberResolver.TryGetValue(memberName, out memberProperty);

pendingMember:
                if (memberProperty == null || memberProperty.GetIndexParameters().Length > 0)
                {
                    global::System.Diagnostics.Debug.WriteLine("JSON Parser: Member '{0}' not found on the object of type '{1}' or requires indices. Skipping.", memberName, targetType);
                    ReadValue(json, ref i, null, null, typeResolver);
                    goto nextMember;
                }

                Type expectedValueType = memberProperty.PropertyType;
                if (typeResolver != null)
                {
                    foreach (JsonMemberTypeInAttribute attribute in memberProperty.GetCustomAttributes <JsonMemberTypeInAttribute>(true))
                    {
                        PropertyInfo typeProperty = targetType.GetProperty(attribute.MemberName);
                        if (typeProperty != null)
                        {
                            if (typeProperty.PropertyType == typeof(Type))
                            {
                                expectedValueType = (Type)typeProperty.GetValue(target, null);
                            }
                            else if (typeProperty.PropertyType == typeof(string))
                            {
                                expectedValueType = typeResolver.ResolveType((string)typeProperty.GetValue(target, null)); // ?? memberProperty.PropertyType;
                            }
                            if (expectedValueType == null)
                            {
                                ResolverPending pending = new ResolverPending {
                                    TypeProperty = typeProperty, MemberProperty = memberProperty, I = i
                                };

                                if (!resolverPendings.Any(p => p == pending))
                                {
                                    resolverPendings.Add(pending);
                                }

                                ReadValue(json, ref i, null, null, null);
                                goto nextMember;
                            }
                        }
                        else
                        {
                            global::System.Diagnostics.Debug.WriteLine("Type property '{0}' not found on object of type '{1}'. Ignoring attribute.", attribute.MemberName, targetType.Name);
                        }
                    }
                }

                if (expectedValueType.Implements <IDictionary>() && memberProperty.GetCustomAttributes <JsonMemberTypeInKeyAttribute>(true).Any())
                {
                    expectedValueType = typeof(TypeInKeyHashtable);
                }

                object currentValue = memberProperty.CanRead ? memberProperty.GetValue(target, null) : null;
                object value        = ReadValue(json, ref i, currentValue, expectedValueType, typeResolver);

                if (!memberProperty.CanWrite)
                {
                    if (value != currentValue)
                    {
                        global::System.Diagnostics.Debug.WriteLine("Member '{0}' is read-only. Skipping.", memberName);
                    }

                    goto nextMember;
                }

                if (value != null)
                {
                    Type valueType = value.GetType();

                    if (!memberProperty.PropertyType.IsAssignableFrom(valueType))
                    {
                        try { value = System.Convert.ChangeType(value, memberProperty.PropertyType, Thread.CurrentThread.CurrentCulture); }
                        catch (Exception e)
                        {
                            global::System.Diagnostics.Debug.WriteLine("Invalid value for member '{0}' of type '{1}'. Skipping. ({2})", memberName, value, e.Message);
                            goto nextMember;
                        }
                    }
                }

                try
                {
                    object oldValue = memberProperty.GetValue(target, null);
                    memberProperty.SetValue(target, value, null);

                    ResolverPending pending = resolverPendings.FirstOrDefault(p => p.TypeProperty == memberProperty);
                    if (pending != null)
                    {
                        resolverPendings.Remove(pending);

                        if (!object.Equals(oldValue, value))
                        {
                            i = pending.I;
                            memberProperty = pending.MemberProperty;

                            global::System.Diagnostics.Debug.WriteLine("Second pass for resolving value type for '{0}'.", memberProperty);
                            goto pendingMember;
                        }
                        else
                        {
                            global::System.Diagnostics.Debug.WriteLine("Value type for '{0}' cannot be resolved. Skipping.", memberProperty);
                        }
                    }
                }
                catch (Exception e)
                {
                    global::System.Diagnostics.Debug.WriteLine("Cannot set value '{0}' to member '{1}'. Skipping. ({2}).", value, memberName, e.Message);
                    goto nextMember;
                }

nextMember:
                SkipWhitespace(json, ref i);

                if (json[i] == '}')
                {
                    break;
                }
                else if (json[i] != ',')
                {
                    throw new FormatException("Unexpected character '" + json[i] + "' at position " + i + ".");
                }

                ++i;
            } while (true);

            ++i; // move after curly bracket

            foreach (ResolverPending pending in resolverPendings)
            {
                global::System.Diagnostics.Debug.WriteLine("Cannot set value '{0}' because the expected type in '{1}' was not supplied. Skipping.", pending.MemberProperty, pending.TypeProperty);
            }
        }
        /// <summary>
        /// Parses a JSON string into an existing object.
        /// </summary>
        /// <typeparam name="T">The type of the object to parse the JSON string into.</typeparam>
        /// <param name="this">The object to parse the JSON string into.</param>
        /// <param name="json">The JSON string to parse.</param>
        /// <param name="typeResolver">A class to help resolving dynamic or unknown types.</param>
        public static void LoadFromJson <T>(this T @this, string json, JsonTypeResolver typeResolver)
        {
            int start = 0;

            LoadFromJson(@this, json, ref start, typeResolver ?? JsonTypeResolver.FromAssemblyMappings <T>());
        }