Exemplo n.º 1
0
        private void SerialiseObjectFieldsAndProperties(
            object value,
            Stack <object> parentsIfReferenceReuseDisallowed,
            Dictionary <object, int> objectHistoryIfReferenceReuseAllowed,
            HashSet <int> deferredInitialisationObjectReferenceIDsIfSupported,
            Dictionary <Type, Action <object> > generatedMemberSetters,
            ISerialisationTypeConverter[] typeConverters,
            IWrite writer)
        {
            // It may be possible for a "type generator" to be created for some types (generally simple types that won't require any nested Serialise calls that involve tracking
            // parentsIfReferenceReuseDisallowed or objectHistoryIfReferenceReuseAllowed), so check that first. There are three cases; 1. we don't have any type generator data
            // about the current type, 2. we have tried to retrieve a type generator before and got back null (meaning that this type does not match the writer's conditions
            // for being able to create a type generator) and 3. we have successfully created a type generator before. If it's case 3 then we'll use that type generator
            // instead of enumerating fields below but if it's case 1 or 2 then we'll have to do that work (but if it's case 1 then we'll try to find out whether it's
            // possible to create a type generator at the bottom of this method).
            var valueType = value.GetType();
            var haveTriedToGenerateMemberSetterBefore = generatedMemberSetters.TryGetValue(valueType, out var memberSetter);

            if (haveTriedToGenerateMemberSetterBefore && (memberSetter != null))
            {
                memberSetter(value);
                return;
            }

            // Write out all of the data for the value
            var(fields, properties) = _typeAnalyser.GetFieldsAndProperties(valueType);
            for (var i = 0; i < fields.Length; i++)
            {
                var field = fields[i];
                if (writer.FieldName(field.Member, valueType))
                {
                    if (parentsIfReferenceReuseDisallowed != null)
                    {
                        parentsIfReferenceReuseDisallowed.Push(value);
                    }
                    var fieldValue = field.Reader(value);
                    Serialise(
                        fieldValue,
                        fieldValue?.GetType() ?? field.Member.FieldType,
                        false,                         // populatingDeferredObject can only refer to the current referene and would never be propagated to member references
                        parentsIfReferenceReuseDisallowed,
                        objectHistoryIfReferenceReuseAllowed,
                        deferredInitialisationObjectReferenceIDsIfSupported,
                        generatedMemberSetters,
                        typeConverters,
                        writer
                        );
                    if (parentsIfReferenceReuseDisallowed != null)
                    {
                        parentsIfReferenceReuseDisallowed.Pop();
                    }
                }
            }
            for (var i = 0; i < properties.Length; i++)
            {
                var property = properties[i];
                if (writer.PropertyName(property.Member, valueType))
                {
                    if (parentsIfReferenceReuseDisallowed != null)
                    {
                        parentsIfReferenceReuseDisallowed.Push(value);
                    }
                    var propertyValue = property.Reader(value);
                    Serialise(
                        propertyValue,
                        propertyValue?.GetType() ?? property.Member.PropertyType,
                        false,                         // populatingDeferredObject can only refer to the current referene and would never be propagated to member references
                        parentsIfReferenceReuseDisallowed,
                        objectHistoryIfReferenceReuseAllowed,
                        deferredInitialisationObjectReferenceIDsIfSupported,
                        generatedMemberSetters,
                        typeConverters,
                        writer
                        );
                    if (parentsIfReferenceReuseDisallowed != null)
                    {
                        parentsIfReferenceReuseDisallowed.Pop();
                    }
                }
            }

            // If we have tried before to create a type generator for this type and were unsuccessful then there is nothing more to do..
            if (haveTriedToGenerateMemberSetterBefore)
            {
                return;
            }

            // .. but if we HAVEN'T tried to create a type generator before then ask the writer if it's able to do so (this is done after the first time that an instance of
            // the type has been fully serialised so that the writer has a chance to create any Name Reference IDs that it might want to use for the member names and potentially
            // have done some other forms of caching)
            generatedMemberSetters[valueType] = writer.TryToGenerateMemberSetter(valueType);
        }