Example #1
0
        /// <summary>
        /// Creates and registers a handler for the specified type according to the rules added so far.
        /// </summary>
        /// <typeparam name="T">The type being serialized.</typeparam>
        /// <returns>The newly created handler.</returns>
        private SerializationHandler AddHandler <T>()
        {
            SerializationHandler handler = null;
            var             type         = typeof(T);
            ISerializer <T> serializer   = null;
            TypeSchema      schema       = null;

            if (!this.knownNames.TryGetValue(type, out string name))
            {
                name = TypeSchema.GetContractName(type, this.runtimeVersion);
            }

            int id = this.schemas.TryGetValue(name, out schema) ? schema.Id : TypeSchema.GetId(name);

            serializer = this.CreateSerializer <T>();
            handler    = SerializationHandler.Create <T>(serializer, name, id);

            // first register the handler
            int oldCount    = this.handlers.Length;
            var newHandlers = new SerializationHandler[oldCount + 1];

            Array.Copy(this.handlers, newHandlers, oldCount);
            newHandlers[oldCount] = handler;
            this.handlers         = newHandlers;

            var newIndex = new Dictionary <SerializationHandler, int>(this.index);

            newIndex[handler] = oldCount;
            this.index        = newIndex;

            var newHandlersByType = new Dictionary <Type, SerializationHandler>(this.handlersByType);

            newHandlersByType[type] = handler;
            this.handlersByType     = newHandlersByType;

            var newHandlersById = new Dictionary <int, SerializationHandler>(this.handlersById);

            newHandlersById[handler.Id] = handler;
            this.handlersById           = newHandlersById;

            // find the schema for this serializer (can be null for interfaces)
            if (serializer != null)
            {
                // initialize the serializer after the handler is registered,
                // to make sure all handlers are registered before initialization runs and
                // allow the serializer initialization code to find and cache the handlers for the types it needs
                schema = serializer.Initialize(this, schema);

                // let any subscribers know that we initialized a new serializer that publishes a schema
                if (schema != null)
                {
                    // store the updated schema and override whatever is present already
                    this.schemas[schema.Name]   = schema;
                    this.schemasById[schema.Id] = schema;
                    this.SchemaAdded?.Invoke(this, schema);
                }
            }

            return(handler);
        }
Example #2
0
        public TypeSchema Initialize(KnownSerializers serializers, TypeSchema targetSchema)
        {
            this.elementHandler = serializers.GetHandler <T>(); // register element type
            var type           = typeof(T[]);
            var name           = TypeSchema.GetContractName(type, serializers.RuntimeVersion);
            var elementsMember = new TypeMemberSchema("Elements", typeof(T).AssemblyQualifiedName, true);
            var schema         = new TypeSchema(name, TypeSchema.GetId(name), type.AssemblyQualifiedName, TypeFlags.IsCollection, new TypeMemberSchema[] { elementsMember }, Version);

            return(targetSchema ?? schema);
        }
Example #3
0
            /// <inheritdoc />
            public TypeSchema Initialize(KnownSerializers serializers, TypeSchema targetSchema)
            {
                // Add a comparerHandler of type IEqualityComparer. This will take care of serializing,
                // deserializing and cloning the Comparer member of Dictionary. Because the comparer field
                // is private, we will also need to generate a dynamic method so that we can set the
                // comparer field upon deserialization or cloning. This method should be invoked right after
                // clearing the target Dictionary, before adding the deserialized or cloned entries to it.
                this.comparerHandler = serializers.GetHandler <IEqualityComparer <TKey> >();
                this.setComparerImpl = this.GenerateSetComparerMethod();

                // Use an array serializer to serialize the dictionary elements as an array of key-value pairs
                this.entriesHandler = serializers.GetHandler <KeyValuePair <TKey, TValue>[]>();

                var type = typeof(Dictionary <TKey, TValue>);
                var name = TypeSchema.GetContractName(type, serializers.RuntimeVersion);

                // Treat the Dictionary as a class with 2 members - a comparer and an array of key-value pairs
                var comparerMember = new TypeMemberSchema("Comparer", typeof(IEqualityComparer <TKey>).AssemblyQualifiedName, true);
                var entriesMember  = new TypeMemberSchema("KeyValuePairs", typeof(KeyValuePair <TKey, TValue>[]).AssemblyQualifiedName, true);
                var schema         = new TypeSchema(name, TypeSchema.GetId(name), type.AssemblyQualifiedName, TypeFlags.IsClass, new[] { comparerMember, entriesMember }, SchemaVersion);

                return(targetSchema ?? schema);
            }
Example #4
0
 // called during codegen, to turn the index of the handler into a constant in the emitted code
 internal int GetIndex(SerializationHandler handler) => this.index[handler];
Example #5
0
        /// <summary>
        /// Creates and registers a handler for the specified type according to the rules added so far.
        /// </summary>
        /// <typeparam name="T">The type being serialized.</typeparam>
        /// <returns>The newly created handler.</returns>
        private SerializationHandler AddHandler <T>()
        {
            SerializationHandler handler = null;
            var             type         = typeof(T);
            ISerializer <T> serializer   = null;
            TypeSchema      schema       = null;

            if (!this.knownNames.TryGetValue(type, out string name))
            {
                name = TypeSchema.GetContractName(type, this.runtimeVersion);
            }

            if (!this.schemas.TryGetValue(name, out schema))
            {
                // try to match to an existing schema without assembly/version info
                string typeName = TypeResolutionHelper.RemoveAssemblyName(type.AssemblyQualifiedName);
                schema = this.schemas.Values.FirstOrDefault(s => TypeResolutionHelper.RemoveAssemblyName(s.TypeName) == typeName);
            }

            int id = schema?.Id ?? TypeSchema.GetId(name);

            serializer = this.CreateSerializer <T>();
            handler    = SerializationHandler.Create <T>(serializer, schema?.Name ?? name, id);

            // first register the handler
            int oldCount    = this.handlers.Length;
            var newHandlers = new SerializationHandler[oldCount + 1];

            Array.Copy(this.handlers, newHandlers, oldCount);
            newHandlers[oldCount] = handler;
            this.handlers         = newHandlers;

            var newIndex = new Dictionary <SerializationHandler, int>(this.index);

            newIndex[handler] = oldCount;
            this.index        = newIndex;

            var newHandlersByType = new Dictionary <Type, SerializationHandler>(this.handlersByType);

            newHandlersByType[type] = handler;
            this.handlersByType     = newHandlersByType;

            var newHandlersById = new Dictionary <int, SerializationHandler>(this.handlersById);

            newHandlersById[handler.Id] = handler;
            this.handlersById           = newHandlersById;

            // find the schema for this serializer (can be null for interfaces)
            if (serializer != null)
            {
                // initialize the serializer after the handler is registered,
                // to make sure all handlers are registered before initialization runs and
                // allow the serializer initialization code to find and cache the handlers for the types it needs
                try
                {
                    schema = serializer.Initialize(this, schema);

                    // let any subscribers know that we initialized a new serializer that publishes a schema
                    if (schema != null)
                    {
                        // store the updated schema and override whatever is present already
                        this.schemas[schema.Name]   = schema;
                        this.schemasById[schema.Id] = schema;
                        this.SchemaAdded?.Invoke(this, schema);
                    }
                }
                catch (SerializationException)
                {
                    // Even though we're going to rethrow this exception, some callers may wish to
                    // attempt to recover from this error and just mark this one stream type as
                    // unreadable. So we should remove the handler we just registered as it's not
                    // yet properly initialized.
                    oldCount    = this.handlers.Length;
                    newHandlers = new SerializationHandler[oldCount - 1];
                    Array.Copy(this.handlers, newHandlers, oldCount - 1);
                    this.handlers = newHandlers;

                    newIndex = new Dictionary <SerializationHandler, int>(this.index);
                    newIndex.Remove(handler);
                    this.index = newIndex;

                    newHandlersByType = new Dictionary <Type, SerializationHandler>(this.handlersByType);
                    newHandlersByType.Remove(type);
                    this.handlersByType = newHandlersByType;

                    newHandlersById = new Dictionary <int, SerializationHandler>(this.handlersById);
                    newHandlersById.Remove(handler.Id);
                    this.handlersById = newHandlersById;

                    throw;
                }
            }

            return(handler);
        }