public void Serialize(JsonWriter jsonWriter, object value, Type objectType)
		{
			if (jsonWriter == null)
				throw new ArgumentNullException("jsonWriter");

			if (objectType != null)
				_rootContract = Serializer._contractResolver.ResolveContract(objectType);

			SerializeValue(jsonWriter, value, GetContractSafe(value), null, null, null);
		}
		private void SerializeValue(JsonWriter writer, object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
		{
			if (value == null)
			{
				writer.WriteNull();
				return;
			}

			JsonConverter converter;
			if ((((converter = (member != null) ? member.Converter : null) != null) || ((converter = (containerProperty != null) ? containerProperty.ItemConverter : null) != null) || ((converter = (containerContract != null) ? containerContract.ItemConverter : null) != null) || ((converter = valueContract.Converter) != null) || ((converter = Serializer.GetMatchingConverter(valueContract.UnderlyingType)) != null) || ((converter = valueContract.InternalConverter) != null)) && converter.CanWrite)
			{
				SerializeConvertable(writer, converter, value, valueContract, containerContract, containerProperty);
				return;
			}

			switch (valueContract.ContractType)
			{
				case JsonContractType.Object:
					SerializeObject(writer, value, (JsonObjectContract) valueContract, member, containerContract, containerProperty);
					break;
				case JsonContractType.Array:
					var arrayContract = (JsonArrayContract) valueContract;
					if (!arrayContract.IsMultidimensionalArray)
						SerializeList(writer, (IEnumerable) value, arrayContract, member, containerContract, containerProperty);
					else
						SerializeMultidimensionalArray(writer, (Array) value, arrayContract, member, containerContract, containerProperty);
					break;
				case JsonContractType.Primitive:
					SerializePrimitive(writer, value, (JsonPrimitiveContract) valueContract, member, containerContract, containerProperty);
					break;
				case JsonContractType.String:
					SerializeString(writer, value, (JsonStringContract) valueContract);
					break;
				case JsonContractType.Dictionary:
					var dictionaryContract = (JsonDictionaryContract) valueContract;
					SerializeDictionary(writer, (value is IDictionary) ? (IDictionary) value : dictionaryContract.CreateWrapper(value), dictionaryContract, member, containerContract, containerProperty);
					break;
#if !(NET35 || NET20 || PORTABLE40)
				case JsonContractType.Dynamic:
					SerializeDynamic(writer, (IDynamicMetaObjectProvider) value, (JsonDynamicContract) valueContract, member, containerContract, containerProperty);
					break;
#endif
#if !(SILVERLIGHT || NETFX_CORE || PORTABLE40 || PORTABLE)
				case JsonContractType.Serializable:
					SerializeISerializable(writer, (ISerializable) value, (JsonISerializableContract) valueContract, member, containerContract, containerProperty);
					break;
#endif
				case JsonContractType.Linq:
					((JToken) value).WriteTo(writer, Serializer.Converters.ToArray());
					break;
			}
		}
		private void OnDeserializing(JsonReader reader, JsonContract contract, object value)
		{
			if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info)
				TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Started deserializing {0}".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType)), null);

			contract.InvokeOnDeserializing(value, Serializer._context);
		}
		private bool ReadForType(JsonReader reader, JsonContract contract, bool hasConverter)
		{
			// don't read properties with converters as a specific value
			// the value might be a string which will then get converted which will error if read as date for example
			if (hasConverter)
				return reader.Read();

			ReadType t = (contract != null) ? contract.InternalReadType : ReadType.Read;

			switch (t)
			{
				case ReadType.Read:
					do
					{
						if (!reader.Read())
							return false;
					} while (reader.TokenType == JsonToken.Comment);

					return true;
				case ReadType.ReadAsInt32:
					reader.ReadAsInt32();
					break;
				case ReadType.ReadAsDecimal:
					reader.ReadAsDecimal();
					break;
				case ReadType.ReadAsBytes:
					reader.ReadAsBytes();
					break;
				case ReadType.ReadAsString:
					reader.ReadAsString();
					break;
				case ReadType.ReadAsDateTime:
					reader.ReadAsDateTime();
					break;
#if !NET20
				case ReadType.ReadAsDateTimeOffset:
					reader.ReadAsDateTimeOffset();
					break;
#endif
				default:
					throw new ArgumentOutOfRangeException();
			}

			return (reader.TokenType != JsonToken.None);
		}
		private bool ShouldWriteType(TypeNameHandling typeNameHandlingFlag, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
		{
			TypeNameHandling resolvedTypeNameHandling = ((member != null) ? member.TypeNameHandling : null) ?? ((containerProperty != null) ? containerProperty.ItemTypeNameHandling : null) ?? ((containerContract != null) ? containerContract.ItemTypeNameHandling : null) ?? Serializer._typeNameHandling;

			if (HasFlag(resolvedTypeNameHandling, typeNameHandlingFlag))
				return true;

			// instance type and the property's type's contract default type are different (no need to put the type in JSON because the type will be created by default)
			if (HasFlag(resolvedTypeNameHandling, TypeNameHandling.Auto))
			{
				if (member != null)
				{
					if (contract.UnderlyingType != member.PropertyContract.CreatedType)
						return true;
				}
				else if (containerContract != null)
				{
					if (containerContract.ItemContract == null || contract.UnderlyingType != containerContract.ItemContract.CreatedType)
						return true;
				}
				else if (_rootContract != null && _serializeStack.Count == 1)
				{
					if (contract.UnderlyingType != _rootContract.CreatedType)
						return true;
				}
			}

			return false;
		}
		private void SerializeConvertable(JsonWriter writer, JsonConverter converter, object value, JsonContract contract, JsonContainerContract collectionContract, JsonProperty containerProperty)
		{
			if (ShouldWriteReference(value, null, contract, collectionContract, containerProperty))
			{
				WriteReference(writer, value);
			}
			else
			{
				if (!CheckForCircularReference(writer, value, null, contract, collectionContract, containerProperty))
					return;

				_serializeStack.Add(value);

				if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info)
					TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(null, writer.Path, "Started serializing {0} with converter {1}.".FormatWith(CultureInfo.InvariantCulture, value.GetType(), converter.GetType())), null);

				converter.WriteJson(writer, value, GetInternalSerializer());

				if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info)
					TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(null, writer.Path, "Finished serializing {0} with converter {1}.".FormatWith(CultureInfo.InvariantCulture, value.GetType(), converter.GetType())), null);

				_serializeStack.RemoveAt(_serializeStack.Count - 1);
			}
		}
		private bool CalculatePropertyValues(JsonWriter writer, object value, JsonContainerContract contract, JsonProperty member, JsonProperty property, out JsonContract memberContract, out object memberValue)
		{
			if (!property.Ignored && property.Readable && ShouldSerialize(writer, property, value) && IsSpecified(writer, property, value))
			{
				if (property.PropertyContract == null)
					property.PropertyContract = Serializer._contractResolver.ResolveContract(property.PropertyType);

				memberValue = property.ValueProvider.GetValue(value);
				memberContract = (property.PropertyContract.IsSealed) ? property.PropertyContract : GetContractSafe(memberValue);

				if (ShouldWriteProperty(memberValue, property))
				{
					if (ShouldWriteReference(memberValue, property, memberContract, contract, member))
					{
						property.WritePropertyName(writer);
						WriteReference(writer, memberValue);
						return false;
					}

					if (!CheckForCircularReference(writer, memberValue, property, memberContract, contract, member))
						return false;

					if (memberValue == null)
					{
						var objectContract = contract as JsonObjectContract;
						Required resolvedRequired = property._required ?? ((objectContract != null) ? objectContract.ItemRequired : null) ?? Required.Default;
						if (resolvedRequired == Required.Always)
							throw JsonSerializationException.Create(null, writer.ContainerPath, "Cannot write a null value for property '{0}'. Property requires a value.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName), null);
					}

					return true;
				}
			}

			memberContract = null;
			memberValue = null;
			return false;
		}
		private bool CheckForCircularReference(JsonWriter writer, object value, JsonProperty property, JsonContract contract, JsonContainerContract containerContract, JsonProperty containerProperty)
		{
			if (value == null || contract.ContractType == JsonContractType.Primitive || contract.ContractType == JsonContractType.String)
				return true;

			ReferenceLoopHandling? referenceLoopHandling = null;

			if (property != null)
				referenceLoopHandling = property.ReferenceLoopHandling;

			if (referenceLoopHandling == null && containerProperty != null)
				referenceLoopHandling = containerProperty.ItemReferenceLoopHandling;

			if (referenceLoopHandling == null && containerContract != null)
				referenceLoopHandling = containerContract.ItemReferenceLoopHandling;

			if (_serializeStack.IndexOf(value) != -1)
			{
				string message = "Self referencing loop detected";
				if (property != null)
					message += " for property '{0}'".FormatWith(CultureInfo.InvariantCulture, property.PropertyName);
				message += " with type '{0}'.".FormatWith(CultureInfo.InvariantCulture, value.GetType());

				switch (referenceLoopHandling.GetValueOrDefault(Serializer._referenceLoopHandling))
				{
					case ReferenceLoopHandling.Error:
						throw JsonSerializationException.Create(null, writer.ContainerPath, message, null);
					case ReferenceLoopHandling.Ignore:
						if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose)
							TraceWriter.Trace(TraceLevel.Verbose, JsonPosition.FormatMessage(null, writer.Path, message + ". Skipping serializing self referenced value."), null);

						return false;
					case ReferenceLoopHandling.Serialize:
						if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose)
							TraceWriter.Trace(TraceLevel.Verbose, JsonPosition.FormatMessage(null, writer.Path, message + ". Serializing self referenced value."), null);

						return true;
				}
			}

			return true;
		}
		private bool ReadSpecialProperties(JsonReader reader, ref Type objectType, ref JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue, out object newValue, out string id)
		{
			id = null;
			newValue = null;

			if (reader.TokenType == JsonToken.PropertyName)
			{
				string propertyName = reader.Value.ToString();

				if (propertyName.Length > 0 && propertyName[0] == '$')
				{
					// read 'special' properties
					// $type, $id, $ref, etc
					bool specialProperty;

					do
					{
						propertyName = reader.Value.ToString();

						if (string.Equals(propertyName, JsonTypeReflector.RefPropertyName, StringComparison.Ordinal))
						{
							CheckedRead(reader);
							if (reader.TokenType != JsonToken.String && reader.TokenType != JsonToken.Null)
								throw JsonSerializationException.Create(reader, "JSON reference {0} property must have a string or null value.".FormatWith(CultureInfo.InvariantCulture, JsonTypeReflector.RefPropertyName));

							string reference = (reader.Value != null) ? reader.Value.ToString() : null;

							CheckedRead(reader);

							if (reference != null)
							{
								if (reader.TokenType == JsonToken.PropertyName)
									throw JsonSerializationException.Create(reader, "Additional content found in JSON reference object. A JSON reference object should only have a {0} property.".FormatWith(CultureInfo.InvariantCulture, JsonTypeReflector.RefPropertyName));

								newValue = Serializer.GetReferenceResolver().ResolveReference(this, reference);

								if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info)
									TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Resolved object reference '{0}' to {1}.".FormatWith(CultureInfo.InvariantCulture, reference, newValue.GetType())), null);

								return true;
							}
							else
							{
								specialProperty = true;
							}
						}
						else if (string.Equals(propertyName, JsonTypeReflector.TypePropertyName, StringComparison.Ordinal))
						{
							CheckedRead(reader);
							string qualifiedTypeName = reader.Value.ToString();

							TypeNameHandling resolvedTypeNameHandling = ((member != null) ? member.TypeNameHandling : null) ?? ((containerContract != null) ? containerContract.ItemTypeNameHandling : null) ?? ((containerMember != null) ? containerMember.ItemTypeNameHandling : null) ?? Serializer._typeNameHandling;

							if (resolvedTypeNameHandling != TypeNameHandling.None)
							{
								string typeName;
								string assemblyName;
								ReflectionUtils.SplitFullyQualifiedTypeName(qualifiedTypeName, out typeName, out assemblyName);

								Type specifiedType;
								try
								{
									specifiedType = Serializer._binder.BindToType(assemblyName, typeName);
								}
								catch (Exception ex)
								{
									throw JsonSerializationException.Create(reader, "Error resolving type specified in JSON '{0}'.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName), ex);
								}

								if (specifiedType == null)
									throw JsonSerializationException.Create(reader, "Type specified in JSON '{0}' was not resolved.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName));

								if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose)
									TraceWriter.Trace(TraceLevel.Verbose, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Resolved type '{0}' to {1}.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName, specifiedType)), null);

								if (objectType != null
#if !(NET35 || NET20 || PORTABLE40)
								    && objectType != typeof (IDynamicMetaObjectProvider)
#endif
								    && !objectType.IsAssignableFrom(specifiedType))
									throw JsonSerializationException.Create(reader, "Type specified in JSON '{0}' is not compatible with '{1}'.".FormatWith(CultureInfo.InvariantCulture, specifiedType.AssemblyQualifiedName, objectType.AssemblyQualifiedName));

								objectType = specifiedType;
								contract = GetContractSafe(specifiedType);
							}

							CheckedRead(reader);

							specialProperty = true;
						}
						else if (string.Equals(propertyName, JsonTypeReflector.IdPropertyName, StringComparison.Ordinal))
						{
							CheckedRead(reader);

							id = (reader.Value != null) ? reader.Value.ToString() : null;

							CheckedRead(reader);
							specialProperty = true;
						}
						else if (string.Equals(propertyName, JsonTypeReflector.ArrayValuesPropertyName, StringComparison.Ordinal))
						{
							CheckedRead(reader);
							object list = CreateList(reader, objectType, contract, member, existingValue, id);
							CheckedRead(reader);
							newValue = list;
							return true;
						}
						else
						{
							specialProperty = false;
						}
					} while (specialProperty && reader.TokenType == JsonToken.PropertyName);
				}
			}
			return false;
		}
		private object CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue)
		{
			CheckedRead(reader);

			string id;
			object newValue;
			if (ReadSpecialProperties(reader, ref objectType, ref contract, member, containerContract, containerMember, existingValue, out newValue, out id))
				return newValue;

			if (HasNoDefinedType(contract))
				return CreateJObject(reader);

			switch (contract.ContractType)
			{
				case JsonContractType.Object:
					{
						bool createdFromNonDefaultConstructor = false;
						var objectContract = (JsonObjectContract) contract;
						object targetObject;
						if (existingValue != null)
							targetObject = existingValue;
						else
							targetObject = CreateNewObject(reader, objectContract, member, containerMember, id, out createdFromNonDefaultConstructor);

						// don't populate if read from non-default constructor because the object has already been read
						if (createdFromNonDefaultConstructor)
							return targetObject;

						return PopulateObject(targetObject, reader, objectContract, member, id);
					}
				case JsonContractType.Primitive:
					{
						var primitiveContract = (JsonPrimitiveContract) contract;
						// if the content is inside $value then read past it
						if (reader.TokenType == JsonToken.PropertyName && string.Equals(reader.Value.ToString(), JsonTypeReflector.ValuePropertyName, StringComparison.Ordinal))
						{
							CheckedRead(reader);

							// the token should not be an object because the $type value could have been included in the object
							// without needing the $value property
							if (reader.TokenType == JsonToken.StartObject)
								throw JsonSerializationException.Create(reader, "Unexpected token when deserializing primitive value: " + reader.TokenType);

							object value = CreateValueInternal(reader, objectType, primitiveContract, member, null, null, existingValue);

							CheckedRead(reader);
							return value;
						}
						break;
					}
				case JsonContractType.Dictionary:
					{
						var dictionaryContract = (JsonDictionaryContract) contract;
						object targetDictionary;

						if (existingValue == null)
						{
							bool createdFromNonDefaultConstructor;
							IDictionary dictionary = CreateNewDictionary(reader, dictionaryContract, out createdFromNonDefaultConstructor);

							if (id != null && createdFromNonDefaultConstructor)
								throw JsonSerializationException.Create(reader, "Cannot preserve reference to readonly dictionary, or dictionary created from a non-default constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));

							if (contract.OnSerializingCallbacks.Count > 0 && createdFromNonDefaultConstructor)
								throw JsonSerializationException.Create(reader, "Cannot call OnSerializing on readonly dictionary, or dictionary created from a non-default constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));

							if (contract.OnErrorCallbacks.Count > 0 && createdFromNonDefaultConstructor)
								throw JsonSerializationException.Create(reader, "Cannot call OnError on readonly list, or dictionary created from a non-default constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));

							PopulateDictionary(dictionary, reader, dictionaryContract, member, id);

							if (createdFromNonDefaultConstructor)
							{
								var constructor = dictionaryContract.ParametrizedConstructor as ConstructorInfo;
								if (constructor != null)
									return constructor.Invoke(new object[] {dictionary});

								return dictionaryContract.ParametrizedConstructor.Invoke(null, new object[] {dictionary});
							}
							else if (dictionary is IWrappedDictionary)
							{
								return ((IWrappedDictionary) dictionary).UnderlyingDictionary;
							}

							targetDictionary = dictionary;
						}
						else
						{
							targetDictionary = PopulateDictionary(dictionaryContract.ShouldCreateWrapper ? dictionaryContract.CreateWrapper(existingValue) : (IDictionary) existingValue, reader, dictionaryContract, member, id);
						}

						return targetDictionary;
					}
#if !(NET35 || NET20 || PORTABLE40)
				case JsonContractType.Dynamic:
					var dynamicContract = (JsonDynamicContract) contract;
					return CreateDynamic(reader, dynamicContract, member, id);
#endif
#if !(SILVERLIGHT || NETFX_CORE || PORTABLE40 || PORTABLE)
				case JsonContractType.Serializable:
					var serializableContract = (JsonISerializableContract) contract;
					return CreateISerializable(reader, serializableContract, member, id);
#endif
			}

			throw JsonSerializationException.Create(reader, @"Cannot deserialize the current JSON object (e.g. {{""name"":""value""}}) into type '{0}' because the type requires a {1} to deserialize correctly.
To fix this error either change the JSON to a {1} or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List<T>) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
".FormatWith(CultureInfo.InvariantCulture, objectType, GetExpectedDescription(contract)));
		}
		private JsonConverter GetConverter(JsonContract contract, JsonConverter memberConverter, JsonContainerContract containerContract, JsonProperty containerProperty)
		{
			JsonConverter converter = null;
			if (memberConverter != null)
			{
				// member attribute converter
				converter = memberConverter;
			}
			else if (containerProperty != null && containerProperty.ItemConverter != null)
			{
				converter = containerProperty.ItemConverter;
			}
			else if (containerContract != null && containerContract.ItemConverter != null)
			{
				converter = containerContract.ItemConverter;
			}
			else if (contract != null)
			{
				JsonConverter matchingConverter;
				if (contract.Converter != null)
					// class attribute converter
					converter = contract.Converter;
				else if ((matchingConverter = Serializer.GetMatchingConverter(contract.UnderlyingType)) != null)
					// passed in converters
					converter = matchingConverter;
				else if (contract.InternalConverter != null)
					// internally specified converter
					converter = contract.InternalConverter;
			}
			return converter;
		}
		internal string GetExpectedDescription(JsonContract contract)
		{
			switch (contract.ContractType)
			{
				case JsonContractType.Object:
				case JsonContractType.Dictionary:
#if !(SILVERLIGHT || NETFX_CORE || PORTABLE || PORTABLE40)
				case JsonContractType.Serializable:
#endif
#if !(NET35 || NET20 || PORTABLE40)
				case JsonContractType.Dynamic:
#endif
					return @"JSON object (e.g. {""name"":""value""})";
				case JsonContractType.Array:
					return @"JSON array (e.g. [1,2,3])";
				case JsonContractType.Primitive:
					return @"JSON primitive value (e.g. string, number, boolean, null)";
				case JsonContractType.String:
					return @"JSON string value";
				default:
					throw new ArgumentOutOfRangeException();
			}
		}
		private object CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue)
		{
			if (contract != null && contract.ContractType == JsonContractType.Linq)
				return CreateJToken(reader, contract);

			do
			{
				switch (reader.TokenType)
				{
						// populate a typed object or generic dictionary/array
						// depending upon whether an objectType was supplied
					case JsonToken.StartObject:
						return CreateObject(reader, objectType, contract, member, containerContract, containerMember, existingValue);
					case JsonToken.StartArray:
						return CreateList(reader, objectType, contract, member, existingValue, null);
					case JsonToken.Integer:
					case JsonToken.Float:
					case JsonToken.Boolean:
					case JsonToken.Date:
					case JsonToken.Bytes:
						return EnsureType(reader, reader.Value, CultureInfo.InvariantCulture, contract, objectType);
					case JsonToken.String:
						var s = (string) reader.Value;

						// convert empty string to null automatically for nullable types
						if (string.IsNullOrEmpty(s) && objectType != typeof (string) && objectType != typeof (object) && contract != null && contract.IsNullable)
							return null;

						// string that needs to be returned as a byte array should be base 64 decoded
						if (objectType == typeof (byte[]))
							return Convert.FromBase64String(s);

						return EnsureType(reader, s, CultureInfo.InvariantCulture, contract, objectType);
					case JsonToken.StartConstructor:
						string constructorName = reader.Value.ToString();

						return EnsureType(reader, constructorName, CultureInfo.InvariantCulture, contract, objectType);
					case JsonToken.Null:
					case JsonToken.Undefined:
#if !(NETFX_CORE || PORTABLE40 || PORTABLE)
						if (objectType == typeof (DBNull))
							return DBNull.Value;
#endif

						return EnsureType(reader, reader.Value, CultureInfo.InvariantCulture, contract, objectType);
					case JsonToken.Raw:
						return new JRaw(reader.Value);
					case JsonToken.Comment:
						// ignore
						break;
					default:
						throw JsonSerializationException.Create(reader, "Unexpected token while deserializing object: " + reader.TokenType);
				}
			} while (reader.Read());

			throw JsonSerializationException.Create(reader, "Unexpected end when deserializing object.");
		}
		private JToken CreateJToken(JsonReader reader, JsonContract contract)
		{
			ValidationUtils.ArgumentNotNull(reader, "reader");

			if (contract != null && contract.UnderlyingType == typeof (JRaw))
			{
				return JRaw.Create(reader);
			}
			else
			{
				JToken token;
				using (var writer = new JTokenWriter())
				{
					writer.WriteToken(reader);
					token = writer.Token;
				}

				return token;
			}
		}
		private bool? ResolveIsReference(JsonContract contract, JsonProperty property, JsonContainerContract collectionContract, JsonProperty containerProperty)
		{
			bool? isReference = null;

			// value could be coming from a dictionary or array and not have a property
			if (property != null)
				isReference = property.IsReference;

			if (isReference == null && containerProperty != null)
				isReference = containerProperty.ItemIsReference;

			if (isReference == null && collectionContract != null)
				isReference = collectionContract.ItemIsReference;

			if (isReference == null)
				isReference = contract.IsReference;

			return isReference;
		}
		private bool ShouldWriteReference(object value, JsonProperty property, JsonContract valueContract, JsonContainerContract collectionContract, JsonProperty containerProperty)
		{
			if (value == null)
				return false;
			if (valueContract.ContractType == JsonContractType.Primitive || valueContract.ContractType == JsonContractType.String)
				return false;

			bool? isReference = ResolveIsReference(valueContract, property, collectionContract, containerProperty);

			if (isReference == null)
			{
				if (valueContract.ContractType == JsonContractType.Array)
					isReference = HasFlag(Serializer._preserveReferencesHandling, PreserveReferencesHandling.Arrays);
				else
					isReference = HasFlag(Serializer._preserveReferencesHandling, PreserveReferencesHandling.Objects);
			}

			if (!isReference.Value)
				return false;

			return Serializer.GetReferenceResolver().IsReferenced(this, value);
		}
		private JsonArrayContract EnsureArrayContract(JsonReader reader, Type objectType, JsonContract contract)
		{
			if (contract == null)
				throw JsonSerializationException.Create(reader, "Could not resolve type '{0}' to a JsonContract.".FormatWith(CultureInfo.InvariantCulture, objectType));

			var arrayContract = contract as JsonArrayContract;
			if (arrayContract == null)
				throw JsonSerializationException.Create(reader, @"Cannot deserialize the current JSON array (e.g. [1,2,3]) into type '{0}' because the type requires a {1} to deserialize correctly.
To fix this error either change the JSON to a {1} or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.
".FormatWith(CultureInfo.InvariantCulture, objectType, GetExpectedDescription(contract)));

			return arrayContract;
		}
		private void OnSerialized(JsonWriter writer, JsonContract contract, object value)
		{
			if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info)
				TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(null, writer.Path, "Finished serializing {0}".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType)), null);

			contract.InvokeOnSerialized(value, Serializer._context);
		}
		private object CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, object existingValue, string id)
		{
			object value;

			if (HasNoDefinedType(contract))
				return CreateJToken(reader, contract);

			JsonArrayContract arrayContract = EnsureArrayContract(reader, objectType, contract);

			if (existingValue == null)
			{
				bool createdFromNonDefaultConstructor;
				IList list = CreateNewList(reader, arrayContract, out createdFromNonDefaultConstructor);

				if (id != null && createdFromNonDefaultConstructor)
					throw JsonSerializationException.Create(reader, "Cannot preserve reference to array or readonly list, or list created from a non-default constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));

				if (contract.OnSerializingCallbacks.Count > 0 && createdFromNonDefaultConstructor)
					throw JsonSerializationException.Create(reader, "Cannot call OnSerializing on an array or readonly list, or list created from a non-default constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));

				if (contract.OnErrorCallbacks.Count > 0 && createdFromNonDefaultConstructor)
					throw JsonSerializationException.Create(reader, "Cannot call OnError on an array or readonly list, or list created from a non-default constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));

				if (!arrayContract.IsMultidimensionalArray)
					PopulateList(list, reader, arrayContract, member, id);
				else
					PopulateMultidimensionalArray(list, reader, arrayContract, member, id);

				if (createdFromNonDefaultConstructor)
				{
					if (arrayContract.IsMultidimensionalArray)
					{
						list = CollectionUtils.ToMultidimensionalArray(list, arrayContract.CollectionItemType, contract.CreatedType.GetArrayRank());
					}
					else if (contract.CreatedType.IsArray)
					{
						Array a = Array.CreateInstance(arrayContract.CollectionItemType, list.Count);
						list.CopyTo(a, 0);
						list = a;
					}
					else
					{
						// call constructor that takes IEnumerable<T>
						var constructor = arrayContract.ParametrizedConstructor as ConstructorInfo;
						if (constructor != null)
							return constructor.Invoke(new object[] {list});

						return arrayContract.ParametrizedConstructor.Invoke(null, new object[] {list});
					}
				}
				else if (list is IWrappedCollection)
				{
					return ((IWrappedCollection) list).UnderlyingCollection;
				}

				value = list;
			}
			else
			{
				value = PopulateList((arrayContract.ShouldCreateWrapper) ? arrayContract.CreateWrapper(existingValue) : (IList) existingValue, reader, arrayContract, member, id);
			}

			return value;
		}
		private void WriteObjectStart(JsonWriter writer, object value, JsonContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
		{
			writer.WriteStartObject();

			bool isReference = ResolveIsReference(contract, member, collectionContract, containerProperty) ?? HasFlag(Serializer._preserveReferencesHandling, PreserveReferencesHandling.Objects);
			if (isReference)
			{
				WriteReferenceIdProperty(writer, contract.UnderlyingType, value);
			}
			if (ShouldWriteType(TypeNameHandling.Objects, contract, member, collectionContract, containerProperty))
			{
				WriteTypeProperty(writer, contract.UnderlyingType);
			}
		}
		private bool HasNoDefinedType(JsonContract contract)
		{
			return (contract == null || contract.UnderlyingType == typeof (object) || contract.ContractType == JsonContractType.Linq
#if !(NET35 || NET20 || PORTABLE40)
			        || contract.UnderlyingType == typeof (IDynamicMetaObjectProvider)
#endif
			       );
		}
		private object EnsureType(JsonReader reader, object value, CultureInfo culture, JsonContract contract, Type targetType)
		{
			if (targetType == null)
				return value;

			Type valueType = ReflectionUtils.GetObjectType(value);

			// type of value and type of target don't match
			// attempt to convert value's type to target's type
			if (valueType != targetType)
			{
				if (value == null && contract.IsNullable)
					return null;

				try
				{
					if (contract.IsConvertable)
					{
						var primitiveContract = (JsonPrimitiveContract) contract;

						if (contract.IsEnum)
						{
							if (value is string)
								return Enum.Parse(contract.NonNullableUnderlyingType, value.ToString(), true);
							else if (ConvertUtils.IsInteger(primitiveContract.TypeCode))
								return Enum.ToObject(contract.NonNullableUnderlyingType, value);
						}

#if !(PORTABLE || PORTABLE40 || NET35 || NET20 || SILVERLIGHT)
						if (value is BigInteger)
							return ConvertUtils.FromBigInteger((BigInteger) value, targetType);
#endif

						// this won't work when converting to a custom IConvertible
						return Convert.ChangeType(value, contract.NonNullableUnderlyingType, culture);
					}

					return ConvertUtils.ConvertOrCast(value, culture, contract.NonNullableUnderlyingType);
				}
				catch (Exception ex)
				{
					throw JsonSerializationException.Create(reader, "Error converting value {0} to type '{1}'.".FormatWith(CultureInfo.InvariantCulture, MiscellaneousUtils.FormatValueForPrint(value), targetType), ex);
				}
			}

			return value;
		}
		private bool CalculatePropertyDetails(JsonProperty property, ref JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, object target, out bool useExistingValue, out object currentValue, out JsonContract propertyContract, out bool gottenCurrentValue)
		{
			currentValue = null;
			useExistingValue = false;
			propertyContract = null;
			gottenCurrentValue = false;

			if (property.Ignored)
				return true;

			JsonToken tokenType = reader.TokenType;

			if (property.PropertyContract == null)
				property.PropertyContract = GetContractSafe(property.PropertyType);

			ObjectCreationHandling objectCreationHandling = property.ObjectCreationHandling.GetValueOrDefault(Serializer._objectCreationHandling);

			if ((objectCreationHandling != ObjectCreationHandling.Replace) && (tokenType == JsonToken.StartArray || tokenType == JsonToken.StartObject) && property.Readable)
			{
				currentValue = property.ValueProvider.GetValue(target);
				gottenCurrentValue = true;

				if (currentValue != null)
				{
					propertyContract = GetContractSafe(currentValue.GetType());

					useExistingValue = (!propertyContract.IsReadOnlyOrFixedSize && !propertyContract.UnderlyingType.IsValueType());
				}
			}

			if (!property.Writable && !useExistingValue)
				return true;

			// test tokentype here because null might not be convertable to some types, e.g. ignoring null when applied to DateTime
			if (property.NullValueHandling.GetValueOrDefault(Serializer._nullValueHandling) == NullValueHandling.Ignore && tokenType == JsonToken.Null)
				return true;

			// test tokentype here because default value might not be convertable to actual type, e.g. default of "" for DateTime
			if (HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer._defaultValueHandling), DefaultValueHandling.Ignore) && !HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer._defaultValueHandling), DefaultValueHandling.Populate) && JsonReader.IsPrimitiveToken(tokenType) && MiscellaneousUtils.ValueEquals(reader.Value, property.GetResolvedDefaultValue()))
				return true;

			if (currentValue == null)
			{
				propertyContract = property.PropertyContract;
			}
			else
			{
				propertyContract = GetContractSafe(currentValue.GetType());

				if (propertyContract != property.PropertyContract)
					propertyConverter = GetConverter(propertyContract, property.MemberConverter, containerContract, containerProperty);
			}

			return false;
		}
		private string GetPropertyName(JsonWriter writer, DictionaryEntry entry, JsonContract contract, out bool escape)
		{
			object key = entry.Key;

			string propertyName;

			var primitiveContract = contract as JsonPrimitiveContract;
			if (primitiveContract != null)
			{
				if (primitiveContract.TypeCode == PrimitiveTypeCode.DateTime || primitiveContract.TypeCode == PrimitiveTypeCode.DateTimeNullable)
				{
					escape = false;
					var sw = new StringWriter(CultureInfo.InvariantCulture);
					DateTimeUtils.WriteDateTimeString(sw, (DateTime) key, writer.DateFormatHandling, writer.DateFormatString, writer.Culture);
					return sw.ToString();
				}
#if !NET20
				else if (primitiveContract.TypeCode == PrimitiveTypeCode.DateTimeOffset || primitiveContract.TypeCode == PrimitiveTypeCode.DateTimeOffsetNullable)
				{
					escape = false;
					var sw = new StringWriter(CultureInfo.InvariantCulture);
					DateTimeUtils.WriteDateTimeOffsetString(sw, (DateTimeOffset) key, writer.DateFormatHandling, writer.DateFormatString, writer.Culture);
					return sw.ToString();
				}
#endif
				else
				{
					escape = true;
					return Convert.ToString(key, CultureInfo.InvariantCulture);
				}
			}
			else if (TryConvertToString(key, key.GetType(), out propertyName))
			{
				escape = true;
				return propertyName;
			}
			else
			{
				escape = true;
				return key.ToString();
			}
		}
		private void ThrowUnexpectedEndException(JsonReader reader, JsonContract contract, object currentObject, string message)
		{
			try
			{
				throw JsonSerializationException.Create(reader, message);
			}
			catch (Exception ex)
			{
				if (IsErrorHandled(currentObject, contract, null, reader as IJsonLineInfo, reader.Path, ex))
					HandleError(reader, false, 0);
				else
					throw;
			}
		}