예제 #1
0
        /// <summary>
        /// Applies the collection data values to a collection instance.
        /// </summary>
        /// <param name="items">The items.</param>
        /// <param name="wireTypeName">Name of the wire type.</param>
        /// <param name="collectionInstance">The collection instance.</param>
        /// <param name="collectionItemType">Type of the collection item.</param>
        /// <param name="addValueToBackingICollectionInstance">The add value to backing I collection instance.</param>
        /// <param name="isElementNullable">If element type is nullable.</param>
        internal void ApplyCollectionDataValues(
            IEnumerable items,
            string wireTypeName,
            object collectionInstance,
            Type collectionItemType,
            Action <object, object> addValueToBackingICollectionInstance,
            bool isElementNullable)
        {
            Debug.Assert(collectionInstance != null, "collectionInstance != null");
            Debug.Assert(WebUtil.IsCLRTypeCollection(collectionInstance.GetType(), this.materializerContext.Model), "collectionInstance must be a CollectionValue");
            Debug.Assert(collectionItemType.IsAssignableFrom(
                             ClientTypeUtil.GetImplementationType(collectionInstance.GetType(), typeof(ICollection <>)).GetGenericArguments()[0]),
                         "collectionItemType has to match the collectionInstance generic type.");
            Debug.Assert(!ClientTypeUtil.TypeIsEntity(collectionItemType, this.materializerContext.Model), "CollectionValues cannot contain entities");
            Debug.Assert(addValueToBackingICollectionInstance != null, "AddValueToBackingICollectionInstance != null");

            // is the Collection not empty ?
            if (items != null)
            {
                bool isCollectionItemTypePrimitive = PrimitiveType.IsKnownNullableType(collectionItemType);

                foreach (object item in items)
                {
                    if (!isElementNullable && item == null)
                    {
                        throw DSClient.Error.InvalidOperation(DSClient.Strings.Collection_NullCollectionItemsNotSupported);
                    }

                    ODataEnumValue enumVal = null;

                    // Is it a Collection of primitive types?
                    if (isCollectionItemTypePrimitive)
                    {
                        if (item is ODataCollectionValue)
                        {
                            throw DSClient.Error.InvalidOperation(DSClient.Strings.Collection_CollectionTypesInCollectionOfPrimitiveTypesNotAllowed);
                        }

                        object materializedValue = this.primitiveValueMaterializationPolicy.MaterializePrimitiveDataValueCollectionElement(collectionItemType, wireTypeName, item);

                        addValueToBackingICollectionInstance(collectionInstance, materializedValue);
                    }
                    else if ((enumVal = item as ODataEnumValue) != null)
                    {
                        // TODO: use EnumValueMaterializationPolicy.MaterializeEnumDataValueCollectionElement() here
                        object tmpValue = EnumValueMaterializationPolicy.MaterializeODataEnumValue(collectionItemType, enumVal);
                        addValueToBackingICollectionInstance(collectionInstance, tmpValue);
                    }
                    else
                    {
                        if (item != null)
                        {
                            throw DSClient.Error.InvalidOperation(DSClient.Strings.Collection_PrimitiveTypesInCollectionOfComplexTypesNotAllowed);
                        }

                        addValueToBackingICollectionInstance(collectionInstance, null);
                    }
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="ODataMaterializer" /> class.
        /// </summary>
        /// <param name="materializerContext">The materializer context.</param>
        /// <param name="expectedType">The expected type.</param>
        protected ODataMaterializer(IODataMaterializerContext materializerContext, Type expectedType)
        {
            this.ExpectedType        = expectedType;
            this.MaterializerContext = materializerContext;
            this.nextLinkTable       = new Dictionary <IEnumerable, DataServiceQueryContinuation>(DSClient.ReferenceEqualityComparer <IEnumerable> .Instance);

            this.enumValueMaterializationPolicy       = new EnumValueMaterializationPolicy(this.MaterializerContext);
            this.lazyPrimitivePropertyConverter       = new DSClient.SimpleLazy <PrimitivePropertyConverter>(() => new PrimitivePropertyConverter(this.Format));
            this.primitiveValueMaterializationPolicy  = new PrimitiveValueMaterializationPolicy(this.MaterializerContext, this.lazyPrimitivePropertyConverter);
            this.collectionValueMaterializationPolicy = new CollectionValueMaterializationPolicy(this.MaterializerContext, this.primitiveValueMaterializationPolicy);
            this.complexValueMaterializerPolicy       = new ComplexValueMaterializationPolicy(this.MaterializerContext, this.lazyPrimitivePropertyConverter);
            this.collectionValueMaterializationPolicy.ComplexValueMaterializationPolicy = this.complexValueMaterializerPolicy;
            this.complexValueMaterializerPolicy.CollectionValueMaterializationPolicy    = this.collectionValueMaterializationPolicy;
        }
예제 #3
0
        /// <summary>
        /// Initializes a new instance of the <see cref="ODataMaterializer" /> class.
        /// </summary>
        /// <param name="materializerContext">The materializer context.</param>
        /// <param name="expectedType">The expected type.</param>
        protected ODataMaterializer(IODataMaterializerContext materializerContext, Type expectedType)
        {
            this.ExpectedType = expectedType;
            this.MaterializerContext = materializerContext;
            this.nextLinkTable = new Dictionary<IEnumerable, DataServiceQueryContinuation>(DSClient.ReferenceEqualityComparer<IEnumerable>.Instance);

            this.enumValueMaterializationPolicy = new EnumValueMaterializationPolicy(this.MaterializerContext);
            this.lazyPrimitivePropertyConverter = new DSClient.SimpleLazy<PrimitivePropertyConverter>(() => new PrimitivePropertyConverter(this.Format));
            this.primitiveValueMaterializationPolicy = new PrimitiveValueMaterializationPolicy(this.MaterializerContext, this.lazyPrimitivePropertyConverter);
            this.collectionValueMaterializationPolicy = new CollectionValueMaterializationPolicy(this.MaterializerContext, this.primitiveValueMaterializationPolicy);
            this.complexValueMaterializerPolicy = new ComplexValueMaterializationPolicy(this.MaterializerContext, this.lazyPrimitivePropertyConverter);
            this.instanceAnnotationMaterializationPolicy = new InstanceAnnotationMaterializationPolicy(this.MaterializerContext);
            this.collectionValueMaterializationPolicy.ComplexValueMaterializationPolicy = this.complexValueMaterializerPolicy;
            this.collectionValueMaterializationPolicy.InstanceAnnotationMaterializationPolicy = this.instanceAnnotationMaterializationPolicy;
            this.complexValueMaterializerPolicy.CollectionValueMaterializationPolicy = this.collectionValueMaterializationPolicy;
            this.complexValueMaterializerPolicy.InstanceAnnotationMaterializationPolicy = this.instanceAnnotationMaterializationPolicy;
            this.instanceAnnotationMaterializationPolicy.ComplexValueMaterializationPolicy = this.complexValueMaterializerPolicy;
            this.instanceAnnotationMaterializationPolicy.CollectionValueMaterializationPolicy = this.collectionValueMaterializationPolicy;
            this.instanceAnnotationMaterializationPolicy.EnumValueMaterializationPolicy = this.enumValueMaterializationPolicy;
        }
예제 #4
0
        /// <summary>
        /// Convert an instance annotation to clr object.
        /// </summary>
        /// <param name="instanceAnnotation">Instance annotation to be converted</param>
        /// <param name="clrInstanceAnnotation">The clr object</param>
        /// <returns>A dictionary of clr-typed instance annotation</returns>
        private bool TryConvertToClrInstanceAnnotation(ODataInstanceAnnotation instanceAnnotation, out object clrInstanceAnnotation)
        {
            clrInstanceAnnotation = null;

            var primitiveValue = instanceAnnotation.Value as ODataPrimitiveValue;

            if (primitiveValue != null)
            {
                clrInstanceAnnotation = primitiveValue.Value;
                return(true);
            }

            var enumValue = instanceAnnotation.Value as ODataEnumValue;

            if (enumValue != null)
            {
                var type = this.MaterializerContext.Context.ResolveTypeFromName(enumValue.TypeName);
                if (type != null)
                {
                    clrInstanceAnnotation = EnumValueMaterializationPolicy.MaterializeODataEnumValue(type, enumValue);
                    return(true);
                }

                return(false);
            }

            var collectionValue = instanceAnnotation.Value as ODataCollectionValue;

            if (collectionValue != null)
            {
                var serverSideModel = this.MaterializerContext.Context.Format.LoadServiceModel();
                var valueTerm       = serverSideModel.FindTerm(instanceAnnotation.Name);

                if (valueTerm != null && valueTerm.Type != null && valueTerm.Type.Definition != null)
                {
                    var edmCollectionType = valueTerm.Type.Definition as IEdmCollectionType;
                    if (edmCollectionType != null)
                    {
                        Type          collectionItemType = null;
                        var           elementType        = edmCollectionType.ElementType;
                        PrimitiveType primitiveType;
                        if (PrimitiveType.TryGetPrimitiveType(elementType.FullName(), out primitiveType))
                        {
                            collectionItemType = primitiveType.ClrType;
                        }
                        else
                        {
                            collectionItemType = this.MaterializerContext.Context.ResolveTypeFromName(elementType.FullName());
                        }

                        if (collectionItemType != null)
                        {
                            Type collectionICollectionType = typeof(ICollection <>).MakeGenericType(new Type[] { collectionItemType });

                            ClientTypeAnnotation collectionClientTypeAnnotation = this.MaterializerContext.ResolveTypeForMaterialization(
                                collectionICollectionType,
                                collectionValue.TypeName);
                            bool isElementNullable = edmCollectionType.ElementType.IsNullable;

                            var collectionInstance = this.CollectionValueMaterializationPolicy.CreateCollectionInstance(
                                collectionClientTypeAnnotation.EdmTypeReference as IEdmCollectionTypeReference,
                                collectionClientTypeAnnotation.ElementType);
                            this.CollectionValueMaterializationPolicy.ApplyCollectionDataValues(
                                collectionValue.Items,
                                collectionValue.TypeName,
                                collectionInstance,
                                collectionItemType,
                                ClientTypeUtil.GetAddToCollectionDelegate(collectionICollectionType),
                                isElementNullable);
                            clrInstanceAnnotation = collectionInstance;
                            return(true);
                        }
                    }
                }

                return(false);
            }

            var nullValue = instanceAnnotation.Value as ODataNullValue;

            if (nullValue != null)
            {
                clrInstanceAnnotation = null;
                return(true);
            }

            return(false);
        }
        /// <summary>
        /// Applies the collection data values to a collection instance.
        /// </summary>
        /// <param name="items">The items.</param>
        /// <param name="wireTypeName">Name of the wire type.</param>
        /// <param name="collectionInstance">The collection instance.</param>
        /// <param name="collectionItemType">Type of the collection item.</param>
        /// <param name="addValueToBackingICollectionInstance">The add value to backing I collection instance.</param>
        /// <param name="isElementNullable">If element type is nullable.</param>
        internal void ApplyCollectionDataValues(
            IEnumerable items,
            string wireTypeName,
            object collectionInstance,
            Type collectionItemType,
            Action <object, object> addValueToBackingICollectionInstance,
            bool isElementNullable)
        {
            Debug.Assert(collectionInstance != null, "collectionInstance != null");
            Debug.Assert(WebUtil.IsCLRTypeCollection(collectionInstance.GetType(), this.materializerContext.Model), "collectionInstance must be a CollectionValue");
            Debug.Assert(collectionItemType.IsAssignableFrom(
                             ClientTypeUtil.GetImplementationType(collectionInstance.GetType(), typeof(ICollection <>)).GetGenericArguments()[0]),
                         "collectionItemType has to match the collectionInstance generic type.");
            Debug.Assert(!ClientTypeUtil.TypeIsEntity(collectionItemType, this.materializerContext.Model), "CollectionValues cannot contain entities");
            Debug.Assert(addValueToBackingICollectionInstance != null, "AddValueToBackingICollectionInstance != null");

            // is the Collection not empty ?
            if (items != null)
            {
                bool isCollectionItemTypePrimitive = PrimitiveType.IsKnownNullableType(collectionItemType);

                foreach (object item in items)
                {
                    if (!isElementNullable && item == null)
                    {
                        throw DSClient.Error.InvalidOperation(DSClient.Strings.Collection_NullCollectionItemsNotSupported);
                    }

                    ODataComplexValue complexValue = item as ODataComplexValue;
                    ODataEnumValue    enumVal      = null;

                    // Is it a Collection of primitive types?
                    if (isCollectionItemTypePrimitive)
                    {
                        // verify that the Collection does not contain complex type items
                        if (complexValue != null || item is ODataCollectionValue)
                        {
                            throw DSClient.Error.InvalidOperation(DSClient.Strings.Collection_ComplexTypesInCollectionOfPrimitiveTypesNotAllowed);
                        }

                        object materializedValue = this.primitiveValueMaterializationPolicy.MaterializePrimitiveDataValueCollectionElement(collectionItemType, wireTypeName, item);

                        addValueToBackingICollectionInstance(collectionInstance, materializedValue);
                    }
                    else if ((enumVal = item as ODataEnumValue) != null)
                    {
                        // TODO: use EnumValueMaterializationPolicy.MaterializeEnumDataValueCollectionElement() here
                        object tmpValue = EnumValueMaterializationPolicy.MaterializeODataEnumValue(collectionItemType, enumVal);
                        addValueToBackingICollectionInstance(collectionInstance, tmpValue);
                    }
                    else
                    {
                        // verify that the Collection does not contain primitive values
                        if (item != null && complexValue == null)
                        {
                            throw DSClient.Error.InvalidOperation(DSClient.Strings.Collection_PrimitiveTypesInCollectionOfComplexTypesNotAllowed);
                        }

                        if (item != null)
                        {
                            ClientTypeAnnotation complexType = this.materializerContext.ResolveTypeForMaterialization(collectionItemType, complexValue.TypeName);
                            object complexInstance           = this.CreateNewInstance(complexType.EdmTypeReference, complexType.ElementType);

                            // set properties with metarialized data values if there are any (note that for a payload that looks as follows <element xmlns="http://docs.oasis-open.org/odata/ns/data"/>
                            // and represents an item that is a complex type there are no properties to be set)
                            this.ComplexValueMaterializationPolicy.ApplyDataValues(complexType, complexValue.Properties, complexInstance);

                            addValueToBackingICollectionInstance(collectionInstance, complexInstance);

                            // Apply instance annotation for complex type item
                            if (!this.materializerContext.Context.DisableInstanceAnnotationMaterialization)
                            {
                                this.InstanceAnnotationMaterializationPolicy.SetInstanceAnnotations(complexValue, complexInstance);
                            }
                        }
                        else
                        {
                            addValueToBackingICollectionInstance(collectionInstance, null);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Adds a data value to the dynamic properties dictionary (where it exists) on the specified <paramref name="instance"/>
        /// </summary>
        /// <param name="property">Property containing unmaterialzed value to apply</param>
        /// <param name="instance">Instance that may optionally contain the dynamic properties dictionary</param>
        internal void MaterializeDynamicProperty(ODataProperty property, object instance)
        {
            Debug.Assert(property != null, "property != null");
            Debug.Assert(instance != null, "instance != null");

            IDictionary <string, object> containerProperty;

            // Stop if owning type is not an open type
            // Or container property is not found
            // Or key with matching name already exists in the dictionary
            if (!ClientTypeUtil.IsInstanceOfOpenType(instance, this.MaterializerContext.Model) ||
                !ClientTypeUtil.TryGetContainerProperty(instance, out containerProperty) ||
                containerProperty.ContainsKey(property.Name))
            {
                return;
            }

            object value = property.Value;

            // Handles properties of known types returned with type annotations
            if (!(value is ODataValue) && PrimitiveType.IsKnownType(value.GetType()))
            {
                containerProperty.Add(property.Name, value);
                return;
            }

            // Handle untyped value
            ODataUntypedValue untypedVal = value as ODataUntypedValue;

            if (untypedVal != null)
            {
                value = CommonUtil.ParseJsonToPrimitiveValue(untypedVal.RawValue);
                containerProperty.Add(property.Name, value);
                return;
            }

            // Handle enum value
            ODataEnumValue enumVal = value as ODataEnumValue;

            if (enumVal != null)
            {
                Type clientType = ResolveClientTypeForDynamicProperty(enumVal.TypeName, instance);
                // Unable to resolve type for dynamic property
                if (clientType == null)
                {
                    return;
                }

                object materializedEnumValue;
                if (EnumValueMaterializationPolicy.TryMaterializeODataEnumValue(clientType, enumVal, out materializedEnumValue))
                {
                    containerProperty.Add(property.Name, materializedEnumValue);
                }

                return;
            }

            // Handle collection
            ODataCollectionValue collectionVal = value as ODataCollectionValue;

            if (collectionVal != null)
            {
                string collectionItemTypeName = CommonUtil.GetCollectionItemTypeName(collectionVal.TypeName, false);
                // Highly unlikely, but the method return null if the typeName argument does not meet certain expectations
                if (collectionItemTypeName == null)
                {
                    return;
                }

                Type collectionItemType;
                // ToNamedType will return true for primitive types
                if (!ClientConvert.ToNamedType(collectionItemTypeName, out collectionItemType))
                {
                    // Non-primitive collection
                    collectionItemType = ResolveClientTypeForDynamicProperty(collectionItemTypeName, instance);
                }

                if (collectionItemType == null)
                {
                    return;
                }

                object collectionInstance;
                if (this.CollectionValueMaterializationPolicy.TryMaterializeODataCollectionValue(collectionItemType, property, out collectionInstance))
                {
                    containerProperty.Add(property.Name, collectionInstance);
                }

                return;
            }
        }
        /// <summary>Applies a data value to the specified <paramref name="instance"/>.</summary>
        /// <param name="type">Type to which a property value will be applied.</param>
        /// <param name="property">Property with value to apply.</param>
        /// <param name="instance">Instance on which value will be applied.</param>
        internal void ApplyDataValue(ClientTypeAnnotation type, ODataProperty property, object instance)
        {
            Debug.Assert(type != null, "type != null");
            Debug.Assert(property != null, "property != null");
            Debug.Assert(instance != null, "instance != null");

            var prop = type.GetProperty(property.Name, this.MaterializerContext.UndeclaredPropertyBehavior);

            if (prop == null)
            {
                return;
            }

            // Is it a collection? (note: property.Properties will be null if the Collection is empty (contains no elements))
            Type enumTypeTmp = null;

            if (prop.IsPrimitiveOrEnumOrComplexCollection)
            {
                // Collections must not be null
                if (property.Value == null)
                {
                    throw DSClient.Error.InvalidOperation(DSClient.Strings.Collection_NullCollectionNotSupported(property.Name));
                }

                // This happens if the payload contain just primitive value for a Collection property
                if (property.Value is string)
                {
                    throw DSClient.Error.InvalidOperation(DSClient.Strings.Deserialize_MixedTextWithComment);
                }

                // ODataLib already parsed the data and materialized all the primitive types. There is nothing more to materialize
                // anymore. Only complex type instance and collection instances need to be materialized, but those will be
                // materialized later on.
                // We need to materialize items before we change collectionInstance since this may throw. If we tried materializing
                // after the Collection is wiped or created we would leave the object in half constructed state.
                object collectionInstance = prop.GetValue(instance);
                if (collectionInstance == null)
                {
                    collectionInstance = this.CollectionValueMaterializationPolicy.CreateCollectionPropertyInstance(property, prop.PropertyType);

                    // allowAdd is false - we need to assign instance as the new property value
                    prop.SetValue(instance, collectionInstance, property.Name, false /* allowAdd? */);
                }
                else
                {
                    // Clear existing Collection
                    prop.ClearBackingICollectionInstance(collectionInstance);
                }

                bool isElementNullable = prop.EdmProperty.Type.AsCollection().ElementType().IsNullable;
                this.CollectionValueMaterializationPolicy.ApplyCollectionDataValues(
                    property,
                    collectionInstance,
                    prop.PrimitiveOrComplexCollectionItemType,
                    prop.AddValueToBackingICollectionInstance,
                    isElementNullable);
            }
            else if ((enumTypeTmp = Nullable.GetUnderlyingType(prop.NullablePropertyType) ?? prop.NullablePropertyType) != null &&
                     enumTypeTmp.IsEnum())
            {
                ODataEnumValue enumValue = property.Value as ODataEnumValue;
                object         tmpValue  = EnumValueMaterializationPolicy.MaterializeODataEnumValue(enumTypeTmp, enumValue);

                // TODO: 1. use EnumValueMaterializationPolicy 2. handle nullable enum property
                prop.SetValue(instance, tmpValue, property.Name, false /* allowAdd? */);
            }
            else
            {
                this.MaterializePrimitiveDataValue(prop.NullablePropertyType, property);
                prop.SetValue(instance, property.GetMaterializedValue(), property.Name, true /* allowAdd? */);
            }

            if (!this.MaterializerContext.Context.DisableInstanceAnnotationMaterialization)
            {
                // Apply instance annotation for Property
                this.InstanceAnnotationMaterializationPolicy.SetInstanceAnnotations(property, type.ElementType, instance);
            }
        }
예제 #8
0
        /// <summary>Applies a data value to the specified <paramref name="instance"/>.</summary>
        /// <param name="type">Type to which a property value will be applied.</param>
        /// <param name="property">Property with value to apply.</param>
        /// <param name="instance">Instance on which value will be applied.</param>
        internal void ApplyDataValue(ClientTypeAnnotation type, ODataProperty property, object instance)
        {
            Debug.Assert(type != null, "type != null");
            Debug.Assert(property != null, "property != null");
            Debug.Assert(instance != null, "instance != null");

            var prop = type.GetProperty(property.Name, this.MaterializerContext.IgnoreMissingProperties);

            if (prop == null)
            {
                return;
            }

            // Is it a collection? (note: property.Properties will be null if the Collection is empty (contains no elements))
            Type enumTypeTmp = null;

            if (prop.IsPrimitiveOrEnumOrComplexCollection)
            {
                // Collections must not be null
                if (property.Value == null)
                {
                    throw DSClient.Error.InvalidOperation(DSClient.Strings.Collection_NullCollectionNotSupported(property.Name));
                }

                // This happens if the payload contain just primitive value for a Collection property
                if (property.Value is string)
                {
                    throw DSClient.Error.InvalidOperation(DSClient.Strings.Deserialize_MixedTextWithComment);
                }

                if (property.Value is ODataComplexValue)
                {
                    throw DSClient.Error.InvalidOperation(DSClient.Strings.AtomMaterializer_InvalidCollectionItem(property.Name));
                }

                // ODataLib already parsed the data and materialized all the primitive types. There is nothing more to materialize
                // anymore. Only complex type instance and collection instances need to be materialized, but those will be
                // materialized later on.
                // We need to materialize items before we change collectionInstance since this may throw. If we tried materializing
                // after the Collection is wiped or created we would leave the object in half constructed state.
                object collectionInstance = prop.GetValue(instance);
                if (collectionInstance == null)
                {
                    collectionInstance = this.CollectionValueMaterializationPolicy.CreateCollectionPropertyInstance(property, prop.PropertyType);

                    // allowAdd is false - we need to assign instance as the new property value
                    prop.SetValue(instance, collectionInstance, property.Name, false /* allowAdd? */);
                }
                else
                {
                    // Clear existing Collection
                    prop.ClearBackingICollectionInstance(collectionInstance);
                }

                bool isElementNullable = prop.EdmProperty.Type.AsCollection().ElementType().IsNullable;
                this.CollectionValueMaterializationPolicy.ApplyCollectionDataValues(
                    property,
                    collectionInstance,
                    prop.PrimitiveOrComplexCollectionItemType,
                    prop.AddValueToBackingICollectionInstance,
                    isElementNullable);
            }
            else if ((enumTypeTmp = Nullable.GetUnderlyingType(prop.NullablePropertyType) ?? prop.NullablePropertyType) != null &&
                     enumTypeTmp.IsEnum)
            {
                ODataEnumValue enumValue = property.Value as ODataEnumValue;
                object         tmpValue  = EnumValueMaterializationPolicy.MaterializeODataEnumValue(enumTypeTmp, enumValue);

                // TODO: 1. use EnumValueMaterializationPolicy 2. handle nullable enum property
                prop.SetValue(instance, tmpValue, property.Name, false /* allowAdd? */);
            }
            else
            {
                object            propertyValue = property.Value;
                ODataComplexValue complexValue  = propertyValue as ODataComplexValue;
                if (propertyValue != null && complexValue != null)
                {
                    if (!prop.EdmProperty.Type.IsComplex())
                    {
                        // The error message is a bit odd, but it's compatible with V1.
                        throw DSClient.Error.InvalidOperation(DSClient.Strings.Deserialize_ExpectingSimpleValue);
                    }

                    // Complex type.
                    bool needToSet = false;

                    ClientEdmModel       edmModel    = this.MaterializerContext.Model;
                    ClientTypeAnnotation complexType = edmModel.GetClientTypeAnnotation(edmModel.GetOrCreateEdmType(prop.PropertyType));
                    object complexInstance           = prop.GetValue(instance);

                    // Validating property inheritance in complexvalue and instance
                    if (prop.PropertyType.Name != property.Name)
                    {
                        complexType = this.MaterializerContext.ResolveTypeForMaterialization(prop.PropertyType, complexValue.TypeName);

                        // recreate complexInstance with derived type
                        complexInstance = null;
                    }

                    if (complexValue.Properties.Any() || complexInstance == null)
                    {
                        complexInstance = this.CreateNewInstance(complexType.EdmTypeReference, complexType.ElementType);
                        needToSet       = true;
                    }

                    this.MaterializeDataValues(complexType, complexValue.Properties, this.MaterializerContext.IgnoreMissingProperties);
                    this.ApplyDataValues(complexType, complexValue.Properties, complexInstance);

                    if (needToSet)
                    {
                        prop.SetValue(instance, complexInstance, property.Name, true /* allowAdd? */);
                    }
                }
                else
                {
                    this.MaterializePrimitiveDataValue(prop.NullablePropertyType, property);
                    prop.SetValue(instance, property.GetMaterializedValue(), property.Name, true /* allowAdd? */);
                }
            }
        }