Beispiel #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);
        }
Beispiel #2
0
            public TypeSchema Initialize(KnownSerializers serializers, TypeSchema targetSchema)
            {
                var schemaMembers = new[] { new TypeMemberSchema("buffer", typeof(byte[]).AssemblyQualifiedName, true) };
                var type          = typeof(MemoryStream);
                var name          = TypeSchema.GetContractName(type, serializers.RuntimeVersion);
                var schema        = new TypeSchema(name, TypeSchema.GetId(name), type.AssemblyQualifiedName, TypeFlags.IsCollection, schemaMembers, SchemaVersion);

                return(targetSchema ?? schema);
            }
Beispiel #3
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);
        }
Beispiel #4
0
        /// <summary>
        /// Registers a given type with the specified contract name.
        /// Use this overload to deserialize data persisted before a type name change.
        /// </summary>
        /// <param name="type">The type to use when deserializing objects with the specified contract.</param>
        /// <param name="contractName">The name to remap. This can be a full type name or a contract name.</param>
        public void Register(Type type, string contractName)
        {
            contractName = contractName ?? TypeSchema.GetContractName(type, this.runtimeVersion);
            if (this.knownTypes.TryGetValue(contractName, out Type existingType) && existingType != type)
            {
                throw new SerializationException($"Cannot register type {type.AssemblyQualifiedName} under the contract name {contractName} because the type {existingType.AssemblyQualifiedName} is already registered under the same name.");
            }

            this.knownTypes[contractName] = type;
            this.knownNames[type]         = contractName;
        }
Beispiel #5
0
        /// <summary>
        /// Registers a given type with the specified contract name.
        /// Use this overload to deserialize data persisted before a type name change.
        /// </summary>
        /// <param name="type">The type to use when deserializing objects with the specified contract.</param>
        /// <param name="contractName">The name to remap. This can be a full type name or a contract name.</param>
        /// <param name="cloningFlags">Optional flags that control the cloning behavior for this type.</param>
        public void Register(Type type, string contractName, CloningFlags cloningFlags = CloningFlags.None)
        {
            contractName = contractName ?? TypeSchema.GetContractName(type, this.runtimeVersion);
            if (this.knownTypes.TryGetValue(contractName, out Type existingType) && existingType != type)
            {
                throw new SerializationException($"Cannot register type {type.AssemblyQualifiedName} under the contract name {contractName} because the type {existingType.AssemblyQualifiedName} is already registered under the same name.");
            }

            if (this.cloningFlags.TryGetValue(type, out var existingFlags) || this.handlersByType.ContainsKey(type))
            {
                // cannot re-register once type flags has been registered or handler has been created
                if (existingFlags != cloningFlags)
                {
                    throw new SerializationException($"Cannot register type {type.AssemblyQualifiedName} with cloning flags ({cloningFlags}) because a handler for it has already been created with flags ({existingFlags}).");
                }
            }

            this.knownTypes[contractName] = type;
            this.knownNames[type]         = contractName;
            this.cloningFlags[type]       = cloningFlags;
        }
Beispiel #6
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);
            }
Beispiel #7
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);
        }