private void SerializeMultidimensionalArray(JsonWriter writer, Array values, JsonArrayContract contract, JsonProperty member, int initialDepth, int[] indices)
		{
			int dimension = indices.Length;
			var 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 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 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 SerializeList(JsonWriter writer, IEnumerable values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
		{
			var 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 (var 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 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)
		{
			var 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;
			var 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;
		}