private object CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, ObjectConstructor<object> creator, string id)
        {
            ValidationUtils.ArgumentNotNull(creator, "creator");

            // only need to keep a track of properies presence if they are required or a value should be defaulted if missing
            Dictionary<JsonProperty, PropertyPresence> propertiesPresence = (contract.HasRequiredOrDefaultValueProperties || HasFlag(Serializer._defaultValueHandling, DefaultValueHandling.Populate))
                ? contract.Properties.ToDictionary(m => m, m => PropertyPresence.None)
                : null;

            Type objectType = contract.UnderlyingType;

            if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info)
            {
                string parameters = string.Join(", ", contract.CreatorParameters.Select(p => p.PropertyName).ToArray());
                TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Deserializing {0} using creator with parameters: {1}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType, parameters)), null);
            }

            IDictionary<string, object> extensionData;
            IDictionary<JsonProperty, object> propertyValues = ResolvePropertyAndCreatorValues(contract, containerProperty, reader, objectType, out extensionData);

            object[] creatorParameterValues = new object[contract.CreatorParameters.Count];
            IDictionary<JsonProperty, object> remainingPropertyValues = new Dictionary<JsonProperty, object>();

            foreach (KeyValuePair<JsonProperty, object> propertyValue in propertyValues)
            {
                JsonProperty matchingCreatorParameter = contract.CreatorParameters.ForgivingCaseSensitiveFind(p => p.PropertyName, propertyValue.Key.PropertyName);
                if (matchingCreatorParameter != null)
                {
                    int i = contract.CreatorParameters.IndexOf(matchingCreatorParameter);
                    creatorParameterValues[i] = propertyValue.Value;
                }
                else
                {
                    remainingPropertyValues.Add(propertyValue);
                }

                if (propertiesPresence != null)
                {
                    // map from creator property to normal property
                    var property = propertiesPresence.Keys.FirstOrDefault(p => p.PropertyName == propertyValue.Key.PropertyName);
                    if (property != null)
                        propertiesPresence[property] = (propertyValue.Value == null) ? PropertyPresence.Null : PropertyPresence.Value;
                }
            }

            object createdObject = creator(creatorParameterValues);

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

            OnDeserializing(reader, contract, createdObject);

            // go through unused values and set the newly created object's properties
            foreach (KeyValuePair<JsonProperty, object> remainingPropertyValue in remainingPropertyValues)
            {
                JsonProperty property = remainingPropertyValue.Key;
                object value = remainingPropertyValue.Value;

                if (ShouldSetPropertyValue(property, value))
                {
                    property.ValueProvider.SetValue(createdObject, value);
                }
                else if (!property.Writable && value != null)
                {
                    // handle readonly collection/dictionary properties
                    JsonContract propertyContract = Serializer._contractResolver.ResolveContract(property.PropertyType);

                    if (propertyContract.ContractType == JsonContractType.Array)
                    {
                        JsonArrayContract propertyArrayContract = (JsonArrayContract)propertyContract;

                        object createdObjectCollection = property.ValueProvider.GetValue(createdObject);
                        if (createdObjectCollection != null)
                        {
                            IWrappedCollection createdObjectCollectionWrapper = propertyArrayContract.CreateWrapper(createdObjectCollection);
                            IWrappedCollection newValues = propertyArrayContract.CreateWrapper(value);

                            foreach (object newValue in newValues)
                            {
                                createdObjectCollectionWrapper.Add(newValue);
                            }
                        }
                    }
                    else if (propertyContract.ContractType == JsonContractType.Dictionary)
                    {
                        JsonDictionaryContract dictionaryContract = (JsonDictionaryContract)propertyContract;

                        object createdObjectDictionary = property.ValueProvider.GetValue(createdObject);
                        if (createdObjectDictionary != null)
                        {
                            IDictionary targetDictionary = (dictionaryContract.ShouldCreateWrapper) ? dictionaryContract.CreateWrapper(createdObjectDictionary) : (IDictionary)createdObjectDictionary;
                            IDictionary newValues = (dictionaryContract.ShouldCreateWrapper) ? dictionaryContract.CreateWrapper(value) : (IDictionary)value;

                            foreach (DictionaryEntry newValue in newValues)
                            {
                                targetDictionary.Add(newValue.Key, newValue.Value);
                            }
                        }
                    }
                }
            }

            if (extensionData != null)
            {
                foreach (KeyValuePair<string, object> e in extensionData)
                {
                    contract.ExtensionDataSetter(createdObject, e.Key, e.Value);
                }
            }

            EndObject(createdObject, reader, contract, reader.Depth, propertiesPresence);

            OnDeserialized(reader, contract, createdObject);
            return createdObject;
        }
        private void SetExtensionData(JsonObjectContract contract, JsonProperty member, JsonReader reader, string memberName, object o)
        {
            if (contract.ExtensionDataSetter != null)
            {
                try
                {
                    object value = CreateValueInternal(reader, null, null, null, contract, member, null);

                    contract.ExtensionDataSetter(o, memberName, value);
                }
                catch (Exception ex)
                {
                    throw JsonSerializationException.Create(reader, "Error setting value in extension data for type '{0}'.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType), ex);
                }
            }
            else
            {
                reader.Skip();
            }
        }
        private object CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, ObjectConstructor<object> creator, string id)
        {
            ValidationUtils.ArgumentNotNull(creator, nameof(creator));

            // only need to keep a track of properies presence if they are required or a value should be defaulted if missing
            bool trackPresence = (contract.HasRequiredOrDefaultValueProperties || HasFlag(Serializer._defaultValueHandling, DefaultValueHandling.Populate));

            Type objectType = contract.UnderlyingType;

            if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info)
            {
                string parameters = string.Join(", ", contract.CreatorParameters.Select(p => p.PropertyName).ToArray());
                TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Deserializing {0} using creator with parameters: {1}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType, parameters)), null);
            }

            List<CreatorPropertyContext> propertyContexts = ResolvePropertyAndCreatorValues(contract, containerProperty, reader, objectType);
            if (trackPresence)
            {
                foreach (JsonProperty property in contract.Properties)
                {
                    if (propertyContexts.All(p => p.Property != property))
                    {
                        propertyContexts.Add(new CreatorPropertyContext
                        {
                            Property = property,
                            Name = property.PropertyName,
                            Presence = PropertyPresence.None
                        });
                    }
                }
            }

            object[] creatorParameterValues = new object[contract.CreatorParameters.Count];

            foreach (CreatorPropertyContext context in propertyContexts)
            {
                // set presence of read values
                if (trackPresence)
                {
                    if (context.Property != null && context.Presence == null)
                    {
                        object v = context.Value;
                        PropertyPresence propertyPresence;
                        if (v == null)
                        {
                            propertyPresence = PropertyPresence.Null;
                        }
                        else if (v is string)
                        {
                            propertyPresence = CoerceEmptyStringToNull(context.Property.PropertyType, context.Property.PropertyContract, (string)v)
                                ? PropertyPresence.Null
                                : PropertyPresence.Value;
                        }
                        else
                        {
                            propertyPresence = PropertyPresence.Value;
                        }

                        context.Presence = propertyPresence;
                    }
                }

                JsonProperty constructorProperty = context.ConstructorProperty;
                if (constructorProperty == null && context.Property != null)
                {
                    constructorProperty = contract.CreatorParameters.ForgivingCaseSensitiveFind(p => p.PropertyName, context.Property.UnderlyingName);
                }

                if (constructorProperty != null && !constructorProperty.Ignored)
                {
                    // handle giving default values to creator parameters
                    // this needs to happen before the call to creator
                    if (trackPresence)
                    {
                        if (context.Presence == PropertyPresence.None || context.Presence == PropertyPresence.Null)
                        {
                            if (constructorProperty.PropertyContract == null)
                            {
                                constructorProperty.PropertyContract = GetContractSafe(constructorProperty.PropertyType);
                            }

                            if (HasFlag(constructorProperty.DefaultValueHandling.GetValueOrDefault(Serializer._defaultValueHandling), DefaultValueHandling.Populate))
                            {
                                context.Value = EnsureType(
                                    reader,
                                    constructorProperty.GetResolvedDefaultValue(),
                                    CultureInfo.InvariantCulture,
                                    constructorProperty.PropertyContract,
                                    constructorProperty.PropertyType);
                            }
                        }
                    }

                    int i = contract.CreatorParameters.IndexOf(constructorProperty);
                    creatorParameterValues[i] = context.Value;

                    context.Used = true;
                }
            }

            object createdObject = creator(creatorParameterValues);

            if (id != null)
            {
                AddReference(reader, id, createdObject);
            }

            OnDeserializing(reader, contract, createdObject);

            // go through unused values and set the newly created object's properties
            foreach (CreatorPropertyContext context in propertyContexts)
            {
                if (context.Used ||
                    context.Property == null ||
                    context.Property.Ignored ||
                    context.Presence == PropertyPresence.None)
                {
                    continue;
                }

                JsonProperty property = context.Property;
                object value = context.Value;

                if (ShouldSetPropertyValue(property, value))
                {
                    property.ValueProvider.SetValue(createdObject, value);
                    context.Used = true;
                }
                else if (!property.Writable && value != null)
                {
                    // handle readonly collection/dictionary properties
                    JsonContract propertyContract = Serializer._contractResolver.ResolveContract(property.PropertyType);

                    if (propertyContract.ContractType == JsonContractType.Array)
                    {
                        JsonArrayContract propertyArrayContract = (JsonArrayContract)propertyContract;

                        object createdObjectCollection = property.ValueProvider.GetValue(createdObject);
                        if (createdObjectCollection != null)
                        {
                            IWrappedCollection createdObjectCollectionWrapper = propertyArrayContract.CreateWrapper(createdObjectCollection);
                            IWrappedCollection newValues = propertyArrayContract.CreateWrapper(value);

                            foreach (object newValue in newValues)
                            {
                                createdObjectCollectionWrapper.Add(newValue);
                            }
                        }
                    }
                    else if (propertyContract.ContractType == JsonContractType.Dictionary)
                    {
                        JsonDictionaryContract dictionaryContract = (JsonDictionaryContract)propertyContract;

                        object createdObjectDictionary = property.ValueProvider.GetValue(createdObject);
                        if (createdObjectDictionary != null)
                        {
                            IDictionary targetDictionary = (dictionaryContract.ShouldCreateWrapper) ? dictionaryContract.CreateWrapper(createdObjectDictionary) : (IDictionary)createdObjectDictionary;
                            IDictionary newValues = (dictionaryContract.ShouldCreateWrapper) ? dictionaryContract.CreateWrapper(value) : (IDictionary)value;

                            foreach (DictionaryEntry newValue in newValues)
                            {
                                targetDictionary.Add(newValue.Key, newValue.Value);
                            }
                        }
                    }

                    context.Used = true;
                }
            }

            if (contract.ExtensionDataSetter != null)
            {
                foreach (CreatorPropertyContext propertyValue in propertyContexts)
                {
                    if (!propertyValue.Used)
                    {
                        contract.ExtensionDataSetter(createdObject, propertyValue.Name, propertyValue.Value);
                    }
                }
            }

            if (trackPresence)
            {
                foreach (CreatorPropertyContext context in propertyContexts)
                {
                    if (context.Property == null)
                    {
                        continue;
                    }

                    EndProcessProperty(
                        createdObject,
                        reader,
                        contract,
                        reader.Depth,
                        context.Property,
                        context.Presence.GetValueOrDefault(),
                        !context.Used);
                }
            }

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