private object PopulateList(IWrappedCollection wrappedList, JsonReader reader, string reference, JsonArrayContract contract)
		{
			object list = wrappedList.UnderlyingCollection;

			// can't populate an existing array
			if (wrappedList.IsFixedSize)
			{
				reader.Skip();
				return wrappedList.UnderlyingCollection;
			}

			if (reference != null)
				Serializer.ReferenceResolver.AddReference(this, reference, list);

			contract.InvokeOnDeserializing(list, Serializer.Context);

			int initialDepth = reader.Depth;

			while (ReadForTypeArrayHack(reader, contract.CollectionItemType))
			{
				switch (reader.TokenType)
				{
					case JsonToken.EndArray:
						contract.InvokeOnDeserialized(list, Serializer.Context);

						return wrappedList.UnderlyingCollection;
					case JsonToken.Comment:
						break;
					default:
						try
						{
							object value = CreateValueNonProperty(reader, contract.CollectionItemType, GetContractSafe(contract.CollectionItemType));

							wrappedList.Add(value);
						}
						catch (Exception ex)
						{
							if (IsErrorHandled(list, contract, wrappedList.Count, ex))
								HandleError(reader, initialDepth);
							else
								throw;
						}
						break;
				}
			}

			throw new JsonSerializationException("Unexpected end when deserializing array.");
		}
		private object PopulateMultidimensionalArray(IList list, JsonReader reader, string reference, JsonArrayContract contract)
		{
			int rank = contract.UnderlyingType.GetArrayRank();

			if (reference != null)
				Serializer.ReferenceResolver.AddReference(this, reference, list);

			contract.InvokeOnDeserializing(list, Serializer.Context);

			//JsonContract collectionItemContract = GetContractSafe(contract.CollectionItemType);
			//JsonConverter collectionItemConverter = GetConverter(collectionItemContract, null, contract, containerProperty);

			//int? previousErrorIndex = null;
			Stack<IList> listStack = new Stack<IList>();
			listStack.Push(list);
			IList currentList = list;

			bool finished = false;
			do
			{
				int initialDepth = reader.Depth;

				if (listStack.Count == rank)
				{
					if (ReadForTypeArrayHack(reader, contract.CollectionItemType))
					{
						switch (reader.TokenType)
						{
							case JsonToken.EndArray:
								listStack.Pop();
								currentList = listStack.Peek();
								//previousErrorIndex = null;
								break;
							case JsonToken.Comment:
								break;
							default:
								try
								{
									object value = CreateValueNonProperty(reader, contract.CollectionItemType, GetContractSafe(contract.CollectionItemType));

									currentList.Add(value);
								}
								catch (Exception ex)
								{
									if (IsErrorHandled(list, contract, currentList.Count, ex))
										HandleError(reader, initialDepth);
									else
										throw;
								}
								break;
						}
					}
					else
					{
						break;
					}


				}
				else
				{
					if (reader.Read())
					{
						switch (reader.TokenType)
						{
							case JsonToken.StartArray:
								IList newList = new List<object>();
								currentList.Add(newList);
								listStack.Push(newList);
								currentList = newList;
								break;
							case JsonToken.EndArray:
								listStack.Pop();

								if (listStack.Count > 0)
								{
									currentList = listStack.Peek();
								}
								else
								{
									finished = true;
								}
								break;
							case JsonToken.Comment:
								break;
							default:
								throw new JsonSerializationException("Unexpected token when deserializing multidimensional array: " + reader.TokenType);
						}
					}
					else
					{
						break;
					}
				}
			} while (!finished);

			if (!finished)
				throw new JsonSerializationException("Unexpected end when deserializing array." + reader.TokenType);

			contract.InvokeOnDeserialized(list, Serializer.Context);
			return list;
		}
    private bool WriteStartArray(JsonWriter writer, object values, JsonArrayContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
    {
      bool isReference = ResolveIsReference(contract, member, containerContract, containerProperty) ?? HasFlag(Serializer._preserveReferencesHandling, PreserveReferencesHandling.Arrays);
      bool includeTypeDetails = ShouldWriteType(TypeNameHandling.Arrays, contract, member, containerContract, containerProperty);
      bool writeMetadataObject = isReference || includeTypeDetails;

      if (writeMetadataObject)
      {
        writer.WriteStartObject();

        if (isReference)
        {
          WriteReferenceIdProperty(writer, contract.UnderlyingType, values);
        }
        if (includeTypeDetails)
        {
          WriteTypeProperty(writer, values.GetType());
        }
        writer.WritePropertyName(JsonTypeReflector.ArrayValuesPropertyName, false);
      }

      if (contract.ItemContract == null)
        contract.ItemContract = Serializer._contractResolver.ResolveContract(contract.CollectionItemType ?? typeof (object));

      return writeMetadataObject;
    }
		private object CreateAndPopulateList(JsonReader reader, string reference, JsonArrayContract contract)
		{
			return CollectionUtils.CreateAndPopulateList(contract.CreatedType, (l, isTemporaryListReference) =>
			{
				if (reference != null && isTemporaryListReference)
					throw new JsonSerializationException("Cannot preserve reference to array or readonly list: {0}".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
				if (contract.OnSerializing != null && isTemporaryListReference)
					throw new JsonSerializationException("Cannot call OnSerializing on an array or readonly list: {0}".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
				if (contract.OnError != null && isTemporaryListReference)
					throw new JsonSerializationException("Cannot call OnError on an array or readonly list: {0}".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));

				if (!contract.IsMultidimensionalArray)
					PopulateList(contract.CreateWrapper(l), reader, reference, contract);
				else
					PopulateMultidimensionalArray(l, reader, reference, contract);
			});
		}
    private void SerializeMultidimensionalArray(JsonWriter writer, Array values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
    {
      OnSerializing(writer, contract, values);

      _serializeStack.Add(values);

      bool hasWrittenMetadataObject = WriteStartArray(writer, values, contract, member, collectionContract, containerProperty);

      SerializeMultidimensionalArray(writer, values, contract, member, writer.Top, new int[0]);

      if (hasWrittenMetadataObject)
        writer.WriteEndObject();

      _serializeStack.RemoveAt(_serializeStack.Count - 1);

      OnSerialized(writer, contract, values);
    }
    private void SerializeMultidimensionalArray(JsonWriter writer, Array values, JsonArrayContract contract, JsonProperty member, int initialDepth, int[] indices)
    {
      int dimension = indices.Length;
      int[] newIndices = new int[dimension + 1];
      for (int i = 0; i < dimension; i++)
      {
        newIndices[i] = indices[i];
      }

      writer.WriteStartArray();

      for (int i = 0; i < values.GetLength(dimension); i++)
      {
        newIndices[dimension] = i;
        bool isTopLevel = (newIndices.Length == values.Rank);

        if (isTopLevel)
        {
          object value = values.GetValue(newIndices);

          try
          {
            JsonContract valueContract = contract.FinalItemContract ?? GetContractSafe(value);

            if (ShouldWriteReference(value, null, valueContract, contract, member))
            {
              WriteReference(writer, value);
            }
            else
            {
              if (CheckForCircularReference(writer, value, null, valueContract, contract, member))
              {
                SerializeValue(writer, value, valueContract, null, contract, member);
              }
            }
          }
          catch (Exception ex)
          {
            if (IsErrorHandled(values, contract, i, null, writer.ContainerPath, ex))
              HandleError(writer, initialDepth + 1);
            else
              throw;
          }
        }
        else
        {
          SerializeMultidimensionalArray(writer, values, contract, member, initialDepth + 1, newIndices);
        }
      }

      writer.WriteEndArray();
    }
    private void SerializeList(JsonWriter writer, IEnumerable values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
    {
      IWrappedCollection wrappedCollection = values as IWrappedCollection;
      object underlyingList = wrappedCollection != null ? wrappedCollection.UnderlyingCollection : values;

      OnSerializing(writer, contract, underlyingList);

      _serializeStack.Add(underlyingList);

      bool hasWrittenMetadataObject = WriteStartArray(writer, underlyingList, contract, member, collectionContract, containerProperty);

      writer.WriteStartArray();

      int initialDepth = writer.Top;

      int index = 0;
      // note that an error in the IEnumerable won't be caught
      foreach (object value in values)
      {
        try
        {
          JsonContract valueContract = contract.FinalItemContract ?? GetContractSafe(value);

          if (ShouldWriteReference(value, null, valueContract, contract, member))
          {
            WriteReference(writer, value);
          }
          else
          {
            if (CheckForCircularReference(writer, value, null, valueContract, contract, member))
            {
              SerializeValue(writer, value, valueContract, null, contract, member);
            }
          }
        }
        catch (Exception ex)
        {
          if (IsErrorHandled(underlyingList, contract, index, null, writer.ContainerPath, ex))
            HandleError(writer, initialDepth);
          else
            throw;
        }
        finally
        {
          index++;
        }
      }

      writer.WriteEndArray();

      if (hasWrittenMetadataObject)
        writer.WriteEndObject();

      _serializeStack.RemoveAt(_serializeStack.Count - 1);

      OnSerialized(writer, contract, underlyingList);
    }
		private void SerializeList(JsonWriter writer, IWrappedCollection values, JsonArrayContract contract, JsonProperty member, JsonContract collectionValueContract)
		{
			contract.InvokeOnSerializing(values.UnderlyingCollection, Serializer.Context);

			SerializeStack.Add(values.UnderlyingCollection);

			bool isReference = contract.IsReference ?? HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Arrays);
			bool includeTypeDetails = ShouldWriteType(TypeNameHandling.Arrays, contract, member, collectionValueContract);

			if (isReference || includeTypeDetails)
			{
				writer.WriteStartObject();

				if (isReference)
				{
					writer.WritePropertyName(JsonTypeReflector.IdPropertyName);
					writer.WriteValue(Serializer.ReferenceResolver.GetReference(this, values.UnderlyingCollection));
				}
				if (includeTypeDetails)
				{
					WriteTypeProperty(writer, values.UnderlyingCollection.GetType());
				}
				writer.WritePropertyName(JsonTypeReflector.ArrayValuesPropertyName);
			}

			JsonContract childValuesContract = Serializer.ContractResolver.ResolveContract(contract.CollectionItemType ?? typeof(object));

			writer.WriteStartArray();

			int initialDepth = writer.Top;

			int index = 0;
			// note that an error in the IEnumerable won't be caught
#if !(UNITY_IPHONE || UNITY_IOS || UNITY_WEBGL || UNITY_XBOXONE || UNITY_XBOX360 || UNITY_PS4 || UNITY_PS3 || UNITY_WII) || (UNITY_IOS || UNITY_WEBGL || UNITY_XBOXONE || UNITY_XBOX360 || UNITY_PS4 || UNITY_PS3 || UNITY_WII && !(UNITY_3_5 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3))
			foreach (object value in values)
			{
				try
				{
					JsonContract valueContract = GetContractSafe(value);

					if (ShouldWriteReference(value, null, valueContract))
					{
						WriteReference(writer, value);
					}
					else
					{
						if (CheckForCircularReference(value, null, contract))
						{
							SerializeValue(writer, value, valueContract, null, childValuesContract);
						}
					}
				}
				catch (Exception ex)
				{
					if (IsErrorHandled(values.UnderlyingCollection, contract, index, ex))
						HandleError(writer, initialDepth);
					else
						throw;
				}
				finally
				{
					index++;
				}
			}
#else

			values.ForEach(value =>
			{
				try
				{
					JsonContract valueContract = GetContractSafe(value);

					if (ShouldWriteReference(value, null, valueContract))
					{
						WriteReference(writer, value);
					}
					else
					{
						if (CheckForCircularReference(value, null, contract))
						{
							SerializeValue(writer, value, valueContract, null, childValuesContract);
						}
					}
				}
				catch (Exception ex)
				{
					if (IsErrorHandled(values.UnderlyingCollection, contract, index, ex))
						HandleError(writer, initialDepth);
					else
						throw;
				}
				finally
				{
					index++;
				}
			});


#endif

			writer.WriteEndArray();

			if (isReference || includeTypeDetails)
			{
				writer.WriteEndObject();
			}

			SerializeStack.RemoveAt(SerializeStack.Count - 1);

			contract.InvokeOnSerialized(values.UnderlyingCollection, Serializer.Context);
		}
    private IList CreateNewList(JsonReader reader, JsonArrayContract contract, out bool createdFromNonDefaultConstructor)
    {
      // some types like non-generic IEnumerable can be serialized but not deserialized
      if (!contract.CanDeserialize)
        throw JsonSerializationException.Create(reader, "Cannot create and populate list type {0}.".FormatWith(CultureInfo.InvariantCulture, contract.CreatedType));

      if (contract.IsReadOnlyOrFixedSize)
      {
        createdFromNonDefaultConstructor = true;
        IList list = contract.CreateTemporaryCollection();

        if (contract.ShouldCreateWrapper)
          list = contract.CreateWrapper(list);

        return list;
      }
      else if (contract.DefaultCreator != null && (!contract.DefaultCreatorNonPublic || Serializer._constructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor))
      {
        object list = contract.DefaultCreator();

        if (contract.ShouldCreateWrapper)
          list = contract.CreateWrapper(list);

        createdFromNonDefaultConstructor = false;
        return (IList)list;
      }
      else if (contract.ParametrizedConstructor != null)
      {
        createdFromNonDefaultConstructor = true;
        return contract.CreateTemporaryCollection();
      }
      else
      {
        throw JsonSerializationException.Create(reader, "Unable to find a constructor to use for type {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
      }
    }
    private object PopulateList(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, string id)
    {
      IWrappedCollection wrappedCollection = list as IWrappedCollection;
      object underlyingList = wrappedCollection != null ? wrappedCollection.UnderlyingCollection : list;

      if (id != null)
        AddReference(reader, id, underlyingList);

      // can't populate an existing array
      if (list.IsFixedSize)
      {
        reader.Skip();
        return underlyingList;
      }

      OnDeserializing(reader, contract, underlyingList);

      int initialDepth = reader.Depth;

      if (contract.ItemContract == null)
        contract.ItemContract = GetContractSafe(contract.CollectionItemType);

      JsonConverter collectionItemConverter = GetConverter(contract.ItemContract, null, contract, containerProperty);

      int? previousErrorIndex = null;

      bool finished = false;
      do
      {
        try
        {
          if (ReadForType(reader, contract.ItemContract, collectionItemConverter != null))
          {
            switch (reader.TokenType)
            {
              case JsonToken.EndArray:
                finished = true;
                break;
              case JsonToken.Comment:
                break;
              default:
                object value;

                if (collectionItemConverter != null && collectionItemConverter.CanRead)
                  value = DeserializeConvertable(collectionItemConverter, reader, contract.CollectionItemType, null);
                else
                  value = CreateValueInternal(reader, contract.CollectionItemType, contract.ItemContract, null, contract, containerProperty, null);

                list.Add(value);
                break;
            }
          }
          else
          {
            break;
          }
        }
        catch (Exception ex)
        {
          JsonPosition errorPosition = reader.GetPosition(initialDepth);

          if (IsErrorHandled(underlyingList, contract, errorPosition.Position, reader as IJsonLineInfo, reader.Path, ex))
          {
            HandleError(reader, true, initialDepth);

            if (previousErrorIndex != null && previousErrorIndex == errorPosition.Position)
            {
              // reader index has not moved since previous error handling
              // break out of reading array to prevent infinite loop
              throw JsonSerializationException.Create(reader, "Infinite loop detected from error handling.", ex);
            }
            else
            {
              previousErrorIndex = errorPosition.Position;
            }
          }
          else
          {
            throw;
          }
        }
      } while (!finished);

      if (!finished)
        ThrowUnexpectedEndException(reader, contract, underlyingList, "Unexpected end when deserializing array.");

      OnDeserialized(reader, contract, underlyingList);
      return underlyingList;
    }
    private object PopulateMultidimensionalArray(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, string id)
    {
      int rank = contract.UnderlyingType.GetArrayRank();

      if (id != null)
        AddReference(reader, id, list);

      OnDeserializing(reader, contract, list);

      JsonContract collectionItemContract = GetContractSafe(contract.CollectionItemType);
      JsonConverter collectionItemConverter = GetConverter(collectionItemContract, null, contract, containerProperty);

      int? previousErrorIndex = null;
      Stack<IList> listStack = new Stack<IList>();
      listStack.Push(list);
      IList currentList = list;

      bool finished = false;
      do
      {
        int initialDepth = reader.Depth;

        if (listStack.Count == rank)
        {
          try
          {
            if (ReadForType(reader, collectionItemContract, collectionItemConverter != null))
            {
              switch (reader.TokenType)
              {
                case JsonToken.EndArray:
                  listStack.Pop();
                  currentList = listStack.Peek();
                  previousErrorIndex = null;
                  break;
                case JsonToken.Comment:
                  break;
                default:
                  object value;

                  if (collectionItemConverter != null && collectionItemConverter.CanRead)
                    value = DeserializeConvertable(collectionItemConverter, reader, contract.CollectionItemType, null);
                  else
                    value = CreateValueInternal(reader, contract.CollectionItemType, collectionItemContract, null, contract, containerProperty, null);

                  currentList.Add(value);
                  break;
              }
            }
            else
            {
              break;
            }
          }
          catch (Exception ex)
          {
            JsonPosition errorPosition = reader.GetPosition(initialDepth);

            if (IsErrorHandled(list, contract, errorPosition.Position, reader as IJsonLineInfo, reader.Path, ex))
            {
              HandleError(reader, true, initialDepth);

              if (previousErrorIndex != null && previousErrorIndex == errorPosition.Position)
              {
                // reader index has not moved since previous error handling
                // break out of reading array to prevent infinite loop
                throw JsonSerializationException.Create(reader, "Infinite loop detected from error handling.", ex);
              }
              else
              {
                previousErrorIndex = errorPosition.Position;
              }
            }
            else
            {
              throw;
            }
          }
        }
        else
        {
          if (reader.Read())
          {
            switch (reader.TokenType)
            {
              case JsonToken.StartArray:
                IList newList = new List<object>();
                currentList.Add(newList);
                listStack.Push(newList);
                currentList = newList;
                break;
              case JsonToken.EndArray:
                listStack.Pop();

                if (listStack.Count > 0)
                {
                  currentList = listStack.Peek();
                }
                else
                {
                  finished = true;
                }
                break;
              case JsonToken.Comment:
                break;
              default:
                throw JsonSerializationException.Create(reader, "Unexpected token when deserializing multidimensional array: " + reader.TokenType);
            }
          }
          else
          {
            break;
          }
        }
      } while (!finished);

      if (!finished)
        ThrowUnexpectedEndException(reader, contract, list, "Unexpected end when deserializing array.");

      OnDeserialized(reader, contract, list);
      return list;
    }