示例#1
0
        // called to find the correct handler for a polymorphic field
        internal SerializationHandler GetUntypedHandler(int handlerId, Type baseType)
        {
            // important: all code paths that could lead to the creation of a new handler need to lock.
            lock (this.syncRoot)
            {
                if (this.handlersById.TryGetValue(handlerId, out SerializationHandler handler))
                {
                    return(handler);
                }
            }

            if (this.schemasById.TryGetValue(handlerId, out TypeSchema schema))
            {
                // do we have a type for this schema name?
                if (!this.knownTypes.TryGetValue(schema.Name, out Type type))
                {
                    // nothing registered, try getting a type based on the type hint
                    type = TypeResolutionHelper.GetVerifiedType(schema.TypeName);
                    if (type == null)
                    {
                        throw new SerializationException($"Failed to create a deserializer for type {schema.Name} because no type was registered for this name and the source type {schema.TypeName} could not be found. Add a reference to the assembly containing this type, or register an alternate type for this name.");
                    }

                    // register the type we found with schema name
                    this.Register(type, schema.Name);
                }

                // this will create the handler if needed
                return(this.GetUntypedHandler(type));
            }

            throw new SerializationException($"Could not find the appropriate derived type with serialization handler id={handlerId} when deserializing a polymorphic instance or field of type {baseType.AssemblyQualifiedName}");
        }
示例#2
0
        /// <inheritdoc/>
        protected override void AddDerivedMemberStreamChildren()
        {
            // Get the type of this node.
            Type dataType = TypeResolutionHelper.GetVerifiedType(this.DataTypeName);

            // If this is already an auto-generated nullable, then the type we care to expand is
            // the value-type inside the nullable type.
            if (this.IsAutoGeneratedNullableMember)
            {
                dataType = dataType.GenericTypeArguments[0];
            }

            // Determine if the current node is a reference type
            var isReference = this.IsAutoGeneratedNullableMember || !dataType.IsValueType || Nullable.GetUnderlyingType(dataType) != null;

            if (dataType != null)
            {
                // Add a child node for each public instance property that takes no parameters.
                foreach (PropertyInfo propertyInfo in dataType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(property => !property.GetMethod.GetParameters().Any()))
                {
                    this.AddDerivedMemberStreamChild(propertyInfo, propertyInfo.PropertyType, isReference && propertyInfo.PropertyType.IsValueType);
                }

                // Add a child node for each public instance field
                foreach (FieldInfo fieldInfo in dataType.GetFields(BindingFlags.Public | BindingFlags.Instance))
                {
                    this.AddDerivedMemberStreamChild(fieldInfo, fieldInfo.FieldType, isReference && fieldInfo.FieldType.IsValueType);
                }
            }
        }
示例#3
0
        /// <inheritdoc/>
        protected override bool CanExpandDerivedMemberStreams()
        {
            // If we have already expanded this node with derived member streams
            if (this.InternalChildren.Any(c => c is DerivedMemberStreamTreeNode))
            {
                // Then no longer expand
                return(false);
            }

            // Get the node type
            var nodeType = TypeResolutionHelper.GetVerifiedType(this.DataTypeName);

            // If it's an auto-generated nullable, we need to assess whether the inner value-type (inside the nullable)
            // can expand the members.
            if (this.IsAutoGeneratedNullableMember)
            {
                nodeType = nodeType.GenericTypeArguments[0];
            }

            if (nodeType != null)
            {
                return(nodeType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(property => !property.GetMethod.GetParameters().Any()).Any() || nodeType.GetFields(BindingFlags.Public | BindingFlags.Instance).Any());
            }

            return(false);
        }
示例#4
0
        /// <summary>
        /// Validate whether two schemas are compatible.
        /// </summary>
        /// <remarks>Schemas are compatible if all required fields are present in both (regardless of type).</remarks>
        /// <param name="other">Other type schema.</param>
        public void ValidateCompatibleWith(TypeSchema other)
        {
            if (this.IsPartial || other == null || other.IsPartial)
            {
                return;
            }

            if ((this.flags & TypeFlags.IsClass) != 0 && (other.flags & TypeFlags.IsStruct) != 0)
            {
                throw new SerializationException($"The type {this.TypeName} changed between versions from struct to class, which is not supported.");
            }
            else if ((this.flags & TypeFlags.IsStruct) != 0 && (other.flags & TypeFlags.IsClass) != 0)
            {
                throw new SerializationException($"The type {this.TypeName} changed between versions from class to struct, which is not supported.");
            }

            // required members in this schema must be present in the other schema
            var requiredAndMissing = this.Members.Where(mbr => mbr.IsRequired && !other.map.ContainsKey(mbr.Name));

            if (requiredAndMissing.Count() > 0)
            {
                if (other.TypeName != this.TypeName)
                {
                    if (TypeResolutionHelper.RemoveCoreAssemblyName(other.TypeName) == TypeResolutionHelper.RemoveCoreAssemblyName(this.TypeName))
                    {
                        throw new SerializationException($"The type {other.TypeName} is not serialization format-compatible across framework versions as it is missing the following members required in the current version of {this.TypeName}: {string.Join(",", requiredAndMissing)}");
                    }
                    else
                    {
                        throw new SerializationException($"The schema {other.Name} version {other.Version} (implemented by {other.TypeName}) is missing the following members required in the current version of {this.TypeName}: {string.Join(",", requiredAndMissing)}");
                    }
                }
                else
                {
                    throw new SerializationException($"The type {this.TypeName} appears to have changed in a way that makes it incompatible with previous versions. The following members required by the new version are missing: {string.Join(",", requiredAndMissing)}");
                }
            }

            // all members in the other schema need to be present in this schema
            requiredAndMissing = other.Members.Where(o => !this.map.ContainsKey(o.Name));
            if (requiredAndMissing.Count() > 0)
            {
                if (other.TypeName != this.TypeName)
                {
                    if (TypeResolutionHelper.RemoveCoreAssemblyName(other.TypeName) == TypeResolutionHelper.RemoveCoreAssemblyName(this.TypeName))
                    {
                        throw new SerializationException($"The type {other.TypeName} is not serialization format-compatible across framework versions as it contains the following members which are not present in the current version of {this.TypeName}: {string.Join(",", requiredAndMissing)}");
                    }
                    else
                    {
                        throw new SerializationException($"The schema {other.Name} version {other.Version} (implemented by {other.TypeName}) contains the following members which are not present in the current version of {this.TypeName}: {string.Join(",", requiredAndMissing)}");
                    }
                }
                else
                {
                    throw new SerializationException($"The type {this.TypeName} appears to have changed in a way that makes it incompatible with previous versions. The following members required by the old version are missing in the new version: {string.Join(",", requiredAndMissing)}");
                }
            }
        }
示例#5
0
        /// <summary>
        /// Registers a generic serializer, that is, a serializer defined for a generic type.
        /// The generic serializer must implement <see cref="ISerializer{T}"/>.
        /// </summary>
        /// <param name="genericSerializer">The type of generic serializer to register.</param>
        public void RegisterGenericSerializer(Type genericSerializer)
        {
            // var interf = genericSerializer.GetInterface("ISerializer`1");
            var interf           = genericSerializer.GetInterface(typeof(ISerializer <>).FullName);
            var serializableType = interf.GetGenericArguments()[0];

            serializableType = TypeResolutionHelper.GetVerifiedType(serializableType.Namespace + "." + serializableType.Name); // FullName doesn't work here
            this.templates[serializableType] = genericSerializer;
        }
示例#6
0
 /// <summary>
 /// Register known types for serialization.
 /// </summary>
 public static void RegisterKnownSerializationTypes()
 {
     KnownSerializers.Default.Register <Queue <TimeSpan> >("System.Collections.Generic.Queue`1[[System.TimeSpan, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], System.Collections, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
     KnownSerializers.Default.Register <Queue <int> >("System.Collections.Generic.Queue`1[[System.Int32, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], System.Collections, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
     KnownSerializers.Default.Register <Dictionary <int, PipelineDiagnostics> >("System.Collections.Generic.Dictionary`2[[System.Int32, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[Microsoft.Psi.Diagnostics.PipelineDiagnostics, Microsoft.Psi, Version=0.7.57.2, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e");
     KnownSerializers.Default.Register <Dictionary <int, PipelineDiagnostics.PipelineElementDiagnostics> >("System.Collections.Generic.Dictionary`2[[System.Int32, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[Microsoft.Psi.Diagnostics.PipelineDiagnostics+PipelineElementDiagnostics, Microsoft.Psi, Version=0.7.57.2, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e");
     KnownSerializers.Default.Register <Dictionary <int, PipelineDiagnostics.ReceiverDiagnostics> >("System.Collections.Generic.Dictionary`2[[System.Int32, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[Microsoft.Psi.Diagnostics.PipelineDiagnostics+ReceiverDiagnostics, Microsoft.Psi, Version=0.7.57.2, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e");
     KnownSerializers.Default.Register <Dictionary <int, PipelineDiagnostics.EmitterDiagnostics> >("System.Collections.Generic.Dictionary`2[[System.Int32, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[Microsoft.Psi.Diagnostics.PipelineDiagnostics+EmitterDiagnostics, Microsoft.Psi, Version=0.7.57.2, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e");
     KnownSerializers.Default.Register(TypeResolutionHelper.GetVerifiedType("System.Collections.Generic.GenericEqualityComparer`1[System.Int32]"), "System.Collections.Generic.GenericEqualityComparer`1[[System.Int32, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e");
 }
示例#7
0
        public void TypeNameTest()
        {
            // primitive type
            string typeName = TypeResolutionHelper.RemoveAssemblyName(typeof(int).AssemblyQualifiedName);

            Assert.AreEqual(typeof(int).FullName, typeName);
            Assert.AreEqual(typeof(int), Type.GetType(typeName));

            typeName = TypeResolutionHelper.RemoveAssemblyName(typeof(int[]).AssemblyQualifiedName);
            Assert.AreEqual(typeof(int[]).FullName, typeName);
            Assert.AreEqual(typeof(int[]), Type.GetType(typeName));

            typeName = TypeResolutionHelper.RemoveAssemblyName(typeof(int[, ]).AssemblyQualifiedName);
            Assert.AreEqual(typeof(int[, ]).FullName, typeName);
            Assert.AreEqual(typeof(int[, ]), Type.GetType(typeName));

            typeName = TypeResolutionHelper.RemoveAssemblyName(typeof(string).AssemblyQualifiedName);
            Assert.AreEqual(typeof(string).FullName, typeName);
            Assert.AreEqual(typeof(string), Type.GetType(typeName));

            typeName = TypeResolutionHelper.RemoveAssemblyName(typeof(object).AssemblyQualifiedName);
            Assert.AreEqual(typeof(object).FullName, typeName);
            Assert.AreEqual(typeof(object), Type.GetType(typeName));

            typeName = TypeResolutionHelper.RemoveAssemblyName(typeof(byte *).AssemblyQualifiedName);
            Assert.AreEqual(typeof(byte *).FullName, typeName);
            Assert.AreEqual(typeof(byte *), Type.GetType(typeName));

            typeName = TypeResolutionHelper.RemoveAssemblyName(typeof(List <>).AssemblyQualifiedName);
            Assert.AreEqual(typeof(List <>).FullName, typeName);
            Assert.AreEqual(typeof(List <>), Type.GetType(typeName));

            // Note - Type.FullName does not remove the AQN from the inner type parameters of generic
            // types, so we won't test the result for equality with typeof(List<int>).FullName
            typeName = TypeResolutionHelper.RemoveAssemblyName(typeof(List <int>).AssemblyQualifiedName);
            Assert.AreEqual(typeof(List <int>), Type.GetType(typeName));

            typeName = TypeResolutionHelper.RemoveAssemblyName(typeof(IEnumerable <int>).AssemblyQualifiedName);
            Assert.AreEqual(typeof(IEnumerable <int>), Type.GetType(typeName));

            typeName = TypeResolutionHelper.RemoveAssemblyName(typeof(IDictionary <int, List <int> >).AssemblyQualifiedName);
            Assert.AreEqual(typeof(IDictionary <int, List <int> >), Type.GetType(typeName));

            typeName = TypeResolutionHelper.RemoveAssemblyName(typeof(Func <int, double>).AssemblyQualifiedName);
            Assert.AreEqual(typeof(Func <int, double>), Type.GetType(typeName));

            typeName = TypeResolutionHelper.RemoveAssemblyName(typeof(NestedClass <List <int> >).AssemblyQualifiedName);
            Assert.AreEqual(typeof(NestedClass <List <int> >), Type.GetType(typeName));

            typeName = TypeResolutionHelper.RemoveAssemblyName("Namespace.TypeName, AssemblyName WithSpaces-v1.0.0.0, Version=1.0.0.0");
            Assert.AreEqual("Namespace.TypeName", typeName);

            typeName = TypeResolutionHelper.RemoveAssemblyName("Namespace.TypeName`2[[Nested.TypeName1, AssemblyName WithSpaces-v1.0.0.0, Version=1.0.0.0], [Nested.TypeName2[], AssemblyName, Culture=neutral]], AssemblyName, PublicKeyToken=null");
            Assert.AreEqual("Namespace.TypeName`2[[Nested.TypeName1], [Nested.TypeName2[]]]", typeName);
        }
示例#8
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
                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);
        }
示例#9
0
 /// <inheritdoc/>
 public Type BindToType(string assemblyName, string typeName)
 {
     return(TypeResolutionHelper.GetVerifiedType($"{typeName}, {assemblyName}"));
 }
示例#10
0
 /// <summary>
 /// Create instance of stream reader (assumes ctor taking name and path.
 /// </summary>
 /// <param name="storeName">Store name.</param>
 /// <param name="storePath">Store path.</param>
 /// <param name="streamReaderTypeName">Stream reader type name.</param>
 /// <returns>Stream reader instance.</returns>
 public static IStreamReader Create(string storeName, string storePath, string streamReaderTypeName)
 {
     return(Create(storeName, storePath, TypeResolutionHelper.GetVerifiedType(streamReaderTypeName)));
 }