Esempio n. 1
0
        /// <summary>
        /// Some writer configurations may perform some upfront analysis based upon the type being serialised. This method should be called by the Serialiser before it starts any
        /// other serialisation process. This will return a dictionary of optimised 'member setters' that the Serialiser may use (a member setter is a delegate that will write the
        /// field and property content for an instance - writing the ObjectStart and ObjectEnd content is the Serialiser's responsibility because that is related to reference-tracking,
        /// which is also the Serialiser's responsibility). Note that this dictionary may include entries that have a null value to indicate that it was not possible generate a member
        /// setter for that type (this may save the Serialiser from calling TryToGenerateMemberSetter for that type later on because it knows that null will be returned). When this
        /// method is called, it will always return a new Dictionary reference and so the caller is free to take ownership of it and mutate it if it wants to. It is not mandatory for
        /// the Serialiser to call this method (and it's not mandatory for it to use the returned dictionary) but it is highly recommended. This should always be called before any
        /// other serialisation methods, calling it after starting serialisation of data will result in an exception being thrown.
        /// </summary>
        public Dictionary <Type, Action <object> > PrepareForSerialisation(Type serialisationTargetType, ISerialisationTypeConverter[] typeConverters)
        {
            if (serialisationTargetType == null)
            {
                throw new ArgumentNullException(nameof(serialisationTargetType));
            }
            if (typeConverters == null)
            {
                throw new ArgumentNullException(nameof(typeConverters));
            }

            if (_haveStartedSerialising)
            {
                throw new Exception(nameof(PrepareForSerialisation) + " must be called before any other serialisation commences");
            }

            // The "BinarySerialisationDeepCompiledMemberSetters.GetMemberSettersFor" method will allow optimised member setters to be generated for more types (which could make
            // the serialisation process much faster) but it may only be used if particular compromises can be made:
            //  - Reference tracking must be disabled (this means that circular references will result in a stack overflow)
            //  - The DefaultTypeAnalyser must be used (because the member setters are cached for reuse and they are generated using the DefaultTypeAnalyser and they may not
            //    be applicable to cases where a different type analyser is required)
            //  - No type converters are used (because these may change the shape of the data during the serialisation process but GetMemberSettersFor needs the data to be remain
            //    in its original form)
            var typeConvertersIsFastTypeConverterArray = (typeConverters is IFastSerialisationTypeConverter[]);

            if ((ReferenceReuseStrategy != ReferenceReuseOptions.SpeedyButLimited) ||
                (_deepMemberSetterCacheIfEnabled == null) ||
                (_typeAnalyser != DefaultTypeAnalyser.Instance) ||
                (!typeConvertersIsFastTypeConverterArray && typeConverters.Any(t => !(t is IFastSerialisationTypeConverter))))
            {
                return(new Dictionary <Type, Action <object> >());
            }

            var fastTypeConverters = typeConvertersIsFastTypeConverterArray
                                ? (IFastSerialisationTypeConverter[])typeConverters
                                : typeConverters.Cast <IFastSerialisationTypeConverter>().ToArray();
            var generatedMemberSetterResult = BinarySerialisationDeepCompiledMemberSetters.GetMemberSettersFor(serialisationTargetType, fastTypeConverters, _deepMemberSetterCacheIfEnabled);

            foreach (var typeName in generatedMemberSetterResult.TypeNamesToDeclare)
            {
                WriteByte((byte)BinarySerialisationDataType.TypeNamePreLoad);
                WriteBytes(typeName.AsStringAndReferenceID);
            }
            foreach (var fieldName in generatedMemberSetterResult.FieldNamesToDeclare)
            {
                WriteByte((byte)BinarySerialisationDataType.FieldNamePreLoad);
                WriteBytes(fieldName.AsStringAndReferenceID);
            }
            return(generatedMemberSetterResult.MemberSetters.ToDictionary(
                       entry => entry.Key,
                       entry => (entry.Value == null) ? null : (Action <object>)(source => entry.Value(source, this))
                       ));
        }
Esempio n. 2
0
        /// <summary>
        /// This will throw a FastestTreeSerialisationNotPossibleException if the specified type does not fully support FastestTreeBinarySerialisation - this may be because
        /// the type is a class that is not sealed or it has a member that is a class that is not sealed or if IntPtr values exist within the object graph (which are not
        /// supported by this serialiser). It will only throw at the first problem because one problem can have knock on effects and so a single property of an unsupported
        /// property type that is deeply nested in the object graph will prevent all of the parent types getting the full-speed treatment.
        ///
        /// This method is intended for us in unit tests in code that references this library - if it is important for this fastest possible serialisation approach to be
        /// used for particular types then it would be sensible to have unit tests that catch any changes to those types that would prevent optimal serialisation performance
        /// because that change is likely to result in a performance regression.
        /// </summary>
        public static void EnsureThatTypeIsOptimalForFastestTreeSerialisation(Type type, IFastSerialisationTypeConverter[] typeConverters)
        {
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }
            if (typeConverters == null)
            {
                throw new ArgumentNullException(nameof(typeConverters));
            }

            // If this method doesn't throw, then great! If it DOES throw then let that exception bubble up to the caller to let them know that all is not well.
            BinarySerialisationDeepCompiledMemberSetters.EnsureThatTypeIsOptimalForFastestTreeSerialisation(type, typeConverters);
        }