/// <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); }
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); }
/// <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); }
// 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];
/// <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); }