示例#1
0
        object CreateValueInternal(
            BitStreamReader reader,
            IContract contract,
            DsdlProperty member,
            ContainerContract containerContract,
            DsdlProperty containerMember,
            object existingValue,
            DsdlType scheme,
            Type objectType,
            bool tailArrayOptimization = false)
        {
            switch (scheme)
            {
            case VoidDsdlType t:
                ReadAlignment(reader, t);
                return(null);

            case PrimitiveDsdlType t:
                var primitive = ReadPrimitiveType(reader, t);
                return(EnsureType(reader, primitive, CultureInfo.InvariantCulture, contract, objectType));

            case ArrayDsdlType t when t.IsStringLike && contract.UnderlyingType == typeof(string):
                var list = CreateList(reader, StringContract, member, null, t, tailArrayOptimization) as IEnumerable <byte>;
                return(_encoding.GetString(list.ToArray()));

            case ArrayDsdlType t:
                return(CreateList(reader, contract, member, existingValue, t, tailArrayOptimization));

            case CompositeDsdlTypeBase t:
                return(CreateObject(reader, contract, member, containerContract, containerMember, existingValue, objectType, t, tailArrayOptimization));

            default:
                throw new ArgumentOutOfRangeException(nameof(scheme));
            }
        }
示例#2
0
        object PopulateList(
            IList list,
            BitStreamReader reader,
            ArrayContract contract,
            DsdlProperty containerProperty,
            ArrayDsdlType scheme,
            bool tailArrayOptimization)
        {
            object underlyingList = list is IWrappedCollection wrappedCollection ? wrappedCollection.UnderlyingCollection : list;

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

            object ReadArrayItem(bool tao = false)
            {
                return(CreateValueInternal(reader, contract.ItemContract, null, contract, containerProperty, null, scheme.ElementType, contract.CollectionItemType, tao));
            }

            switch (scheme.Mode)
            {
            case ArrayDsdlTypeMode.Static:
            {
                for (int i = 0; i < scheme.MaxSize; i++)
                {
                    list.Add(ReadArrayItem());
                }
                break;
            }

            case ArrayDsdlTypeMode.Dynamic:
            {
                if (tailArrayOptimization && scheme.ElementType.MinBitlen >= 8)
                {
                    while (reader.LengthInBytes - reader.CurrentIndex > 1)
                    {
                        list.Add(ReadArrayItem());
                    }
                }
                else
                {
                    var arraySize = ReadDynamicArraySize(reader, scheme);
                    for (int i = 0; i < arraySize; i++)
                    {
                        var tao = i == arraySize - 1 ? tailArrayOptimization : false;
                        list.Add(ReadArrayItem(tao));
                    }
                }
                break;
            }

            default:
                throw new ArgumentOutOfRangeException(nameof(ArrayDsdlTypeMode));
            }

            return(underlyingList);
        }
示例#3
0
        private bool ShouldSetPropertyValue(DsdlProperty property, ObjectContract contract, object value)
        {
            if (!property.Writable)
            {
                return(false);
            }

            return(true);
        }
示例#4
0
        object PopulateDictionary(
            IDictionary dictionary,
            BitStreamReader reader,
            DictionaryContract contract,
            DsdlProperty containerProperty,
            CompositeDsdlTypeBase scheme,
            bool tailArrayOptimization)
        {
            object underlyingDictionary = dictionary is IWrappedDictionary wrappedDictionary ? wrappedDictionary.UnderlyingDictionary : dictionary;

            if (contract.KeyContract == null)
            {
                contract.KeyContract = GetContractSafe(contract.DictionaryKeyType);
            }

            if (contract.ItemContract == null)
            {
                contract.ItemContract = GetContractSafe(contract.DictionaryValueType);
            }

            foreach (var(field, tao) in EnumerateSchemeFields(reader, scheme, tailArrayOptimization))
            {
                if (field.Type is VoidDsdlType t)
                {
                    ReadAlignment(reader, t);
                    continue;
                }

                var keyValue = EnsureType(reader, field.Name, CultureInfo.InvariantCulture, contract.KeyContract, contract.DictionaryKeyType);

                var itemValue = CreateValueInternal(reader,
                                                    contract.ItemContract,
                                                    null,
                                                    contract,
                                                    containerProperty,
                                                    null,
                                                    field.Type,
                                                    null,
                                                    tao);

                dictionary[keyValue] = itemValue;
            }

            return(underlyingDictionary);
        }
示例#5
0
        bool CheckForCircularReference(object value, DsdlProperty property, IContract contract)
        {
            if (value == null || contract is PrimitiveContract)
            {
                return(true);
            }

            if (_serializeStack.Contains(value))
            {
                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());

                throw new SerializationException(message);
            }

            return(true);
        }
示例#6
0
        bool CalculatePropertyValues(object value, ContainerContract contract, DsdlProperty property, out IContract memberContract, out object memberValue)
        {
            memberContract = null;
            memberValue    = null;

            if (property.Ignored || !property.Readable)
            {
                return(false);
            }

            memberValue = property.ValueProvider.GetValue(value);
            if (memberValue == null)
            {
                return(false);
            }

            if (property.PropertyContract == null)
            {
                property.PropertyContract = _serializer.ContractResolver.ResolveContract(property.PropertyType);
            }

            memberContract = (property.PropertyContract.IsSealed) ?
                             property.PropertyContract :
                             _serializer.ContractResolver.ResolveContract(memberValue.GetType());

            if (!CheckForCircularReference(memberValue, property, memberContract))
            {
                return(false);
            }

            if (!CheckDsdlTypeCompatibility(property.DsdlType, memberContract))
            {
                throw new InvalidOperationException(
                          $"DSDL type mismatch for property '{contract.UnderlyingType.FullName}.{property.UnderlyingName}'.");
            }

            return(true);
        }
示例#7
0
        private object PopulateObject(
            object newObject,
            BitStreamReader
            reader,
            ObjectContract contract,
            DsdlProperty member,
            CompositeDsdlTypeBase scheme,
            bool tailArrayOptimization)
        {
            foreach (var(field, tao) in EnumerateSchemeFields(reader, scheme, tailArrayOptimization))
            {
                if (field.Type is VoidDsdlType t)
                {
                    ReadAlignment(reader, t);
                    continue;
                }

                // attempt exact case match first
                // then try match ignoring case
                DsdlProperty property = contract.Properties.GetClosestMatchProperty(field.Name);

                if (property == null)
                {
                    throw new SerializationException($"Could not find member '{field.Name}' on object of type '{contract.UnderlyingType.FullName}'");
                }

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

                SetPropertyValue(property, contract, member, reader, newObject, field.Type, tao);
            }

            return(newObject);
        }
示例#8
0
        public object CreateNewObject(BitStreamReader reader, ObjectContract objectContract, DsdlProperty containerMember, DsdlProperty containerProperty, out bool createdFromNonDefaultCreator)
        {
            object newObject = null;

            if (objectContract.DefaultCreator != null && !objectContract.DefaultCreatorNonPublic)
            {
                // use the default constructor if it is...
                // public
                // non-public and the user has change constructor handling settings
                // non-public and there is no other creator
                newObject = objectContract.DefaultCreator();
            }

            if (newObject == null)
            {
                if (!objectContract.IsInstantiable)
                {
                    throw new SerializationException("Could not create an instance of type {0}. Type is an interface or abstract class and cannot be instantiated.".FormatWith(CultureInfo.InvariantCulture, objectContract.UnderlyingType));
                }

                throw new SerializationException("Unable to find a constructor to use for type {0}. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute.".FormatWith(CultureInfo.InvariantCulture, objectContract.UnderlyingType));
            }

            createdFromNonDefaultCreator = false;
            return(newObject);
        }
示例#9
0
        bool SetPropertyValue(
            DsdlProperty property,
            ContainerContract containerContract,
            DsdlProperty containerProperty,
            BitStreamReader reader,
            object target,
            DsdlType scheme,
            bool tailArrayOptimization)
        {
            if (property.Ignored)
            {
                return(true);
            }

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

            bool   useExistingValue = false;
            object currentValue     = null;

            if (property.Readable)
            {
                currentValue = property.ValueProvider.GetValue(target);
            }

            IContract propertyContract;

            if (currentValue == null)
            {
                propertyContract = property.PropertyContract;
            }
            else
            {
                propertyContract = GetContractSafe(currentValue.GetType());
                useExistingValue = (!propertyContract.IsReadOnlyOrFixedSize && !propertyContract.UnderlyingType.IsValueType());
            }

            var value = CreateValueInternal(
                reader,
                propertyContract,
                property,
                containerContract,
                containerProperty,
                (useExistingValue) ? currentValue : null,
                scheme,
                property.PropertyType,
                tailArrayOptimization);

            // always set the value if useExistingValue is false,
            // otherwise also set it if CreateValue returns a new value compared to the currentValue
            // this could happen because of a JsonConverter against the type
            if ((!useExistingValue || value != currentValue) &&
                ShouldSetPropertyValue(property, containerContract as ObjectContract, value))
            {
                property.ValueProvider.SetValue(target, value);

                return(true);
            }

            // the value wasn't set be JSON was populated onto the existing value
            return(useExistingValue);
        }
示例#10
0
        object CreateList(
            BitStreamReader reader,
            IContract contract,
            DsdlProperty member,
            object existingValue,
            ArrayDsdlType scheme,
            bool tailArrayOptimization)
        {
            if (HasNoDefinedType(contract))
            {
                return(CreateUnknownObject(reader, scheme, tailArrayOptimization));
            }

            if (!(contract is ArrayContract arrayContract))
            {
                throw new SerializationException("Could not resolve type to IContract.");
            }

            if (existingValue == null)
            {
                var list = CreateNewList(reader, arrayContract, out bool createdFromNonDefaultCreator);

                if (createdFromNonDefaultCreator && !arrayContract.HasParameterizedCreatorInternal && !arrayContract.IsArray)
                {
                    throw new SerializationException($"Cannot deserialize readonly or fixed size list: {contract.UnderlyingType}.");
                }
                if (arrayContract.IsMultidimensionalArray)
                {
                    throw new NotSupportedException("Multidimensional arrays are not supported.");
                }

                PopulateList(list, reader, arrayContract, member, scheme, tailArrayOptimization);

                if (createdFromNonDefaultCreator)
                {
                    if (arrayContract.IsArray)
                    {
                        Array a = Array.CreateInstance(arrayContract.CollectionItemType, list.Count);
                        list.CopyTo(a, 0);
                        list = a;
                    }
                    else
                    {
                        ObjectConstructor <object> creator = arrayContract.OverrideCreator ?? arrayContract.ParameterizedCreator;

                        return(creator(list));
                    }
                }
                else if (list is IWrappedCollection wrappedCollection)
                {
                    return(wrappedCollection.UnderlyingCollection);
                }

                return(list);
            }
            else
            {
                if (!arrayContract.CanDeserialize)
                {
                    throw new SerializationException($"Cannot populate list type {contract.CreatedType}.");
                }

                return(PopulateList(
                           (arrayContract.ShouldCreateWrapper || !(existingValue is IList list)) ? arrayContract.CreateWrapper(existingValue) : list,
                           reader,
                           arrayContract,
                           member,
                           scheme,
                           tailArrayOptimization));
            }
        }
示例#11
0
        object CreateObject(
            BitStreamReader reader,
            IContract contract,
            DsdlProperty member,
            ContainerContract containerContract,
            DsdlProperty containerMember,
            object existingValue,
            Type objectType,
            CompositeDsdlTypeBase scheme,
            bool tailArrayOptimization)
        {
            if (HasNoDefinedType(contract))
            {
                return(CreateUnknownObject(reader, scheme));
            }

            switch (contract)
            {
            case ObjectContract objectContract:
            {
                bool   createdFromNonDefaultCreator = false;
                object targetObject;
                // check that if type name handling is being used that the existing value is compatible with the specified type
                if (existingValue != null && objectType != null && objectType.IsAssignableFrom(existingValue.GetType()))
                {
                    targetObject = existingValue;
                }
                else
                {
                    targetObject = CreateNewObject(reader, objectContract, member, containerMember, out createdFromNonDefaultCreator);
                }

                // don't populate if read from non-default creator because the object has already been read
                if (createdFromNonDefaultCreator)
                {
                    return(targetObject);
                }

                return(PopulateObject(targetObject, reader, objectContract, member, scheme, tailArrayOptimization));
            }

            case DictionaryContract dictionaryContract:
            {
                object targetDictionary;

                if (existingValue == null)
                {
                    var dictionary = CreateNewDictionary(reader, dictionaryContract, out bool createdFromNonDefaultCreator);

                    if (createdFromNonDefaultCreator && !dictionaryContract.HasParameterizedCreatorInternal)
                    {
                        throw new SerializationException("Cannot deserialize readonly or fixed size dictionary: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
                    }

                    PopulateDictionary(dictionary, reader, dictionaryContract, member, scheme, tailArrayOptimization);

                    if (createdFromNonDefaultCreator)
                    {
                        ObjectConstructor <object> creator = dictionaryContract.OverrideCreator ?? dictionaryContract.ParameterizedCreator;

                        return(creator(dictionary));
                    }
                    else if (dictionary is IWrappedDictionary wrappedDictionary)
                    {
                        return(wrappedDictionary.UnderlyingDictionary);
                    }

                    targetDictionary = dictionary;
                }
                else
                {
                    targetDictionary = PopulateDictionary(
                        dictionaryContract.ShouldCreateWrapper || !(existingValue is IDictionary) ? dictionaryContract.CreateWrapper(existingValue) : (IDictionary)existingValue,
                        reader,
                        dictionaryContract,
                        member,
                        scheme,
                        tailArrayOptimization);
                }

                return(targetDictionary);
            }
            }

            throw new SerializationException($"Cannot deserialize the current object.");
        }