Esempio n. 1
0
        /// <summary>
        /// Determines whether an instance of the specified type must be cleared prior to reuse
        /// as a cloning or deserialization target.
        /// </summary>
        /// <param name="type">The type to check.</param>
        /// <param name="serializers">A registry of known serializers.</param>
        /// <returns>true if the type requires clearing prior to reuse; otherwise, false.</returns>
        internal static bool IsClearRequired(Type type, KnownSerializers serializers)
        {
            // first check whether a cached result exists
            var handler = serializers.GetUntypedHandler(type);

            if (handler.IsClearRequired.HasValue)
            {
                return(handler.IsClearRequired.Value);
            }

            // Initialize the cached value so that we know that we have seen it if we encounter it again during
            // the current evaluation (i.e. if the object graph contains a cycle back to the current type).
            handler.IsClearRequired = false;

            // Skip evaluation for simple value types and strings. Otherwise, clearing is only required
            // for Shared<> types, arrays of Shared<>, or object graphs which may contain a Shared<>.
            bool result =
                !IsSimpleValueType(type) &&
                type != typeof(string) &&
                ((type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Shared <>)) ||
                 (type.IsArray && IsClearRequired(type.GetElementType(), serializers)) ||
                 GetSerializableFields(type).Any(fi => IsClearRequired(fi.FieldType, serializers)));

            // cache the result
            handler.IsClearRequired = result;

            return(result);
        }
Esempio n. 2
0
        // emits code to clear all the fields (public, private, readonly) that meet the specified criteria
        internal static void EmitClearFields(Type type, KnownSerializers serializers, ILGenerator il)
        {
            // simply invoke the type serializer for each relevant field
            foreach (FieldInfo field in GetClonableFields(type))
            {
                if (IsSimpleValueType(field.FieldType) || field.FieldType == typeof(string))
                {
                    continue;
                }

                // find the right handler
                var handler = serializers.GetUntypedHandler(field.FieldType);
                int index   = serializers.GetIndex(handler);

                // argument legend: 0 = ref target, 1 = context
                il.Emit(OpCodes.Ldarg_1);                         // push context
                il.Emit(OpCodes.Ldc_I4, index);                   // push the serializer id
                il.Emit(OpCodes.Call, GetHandlerFromIndexMethod); // call GetHandler to push the handler

                // handler.Clear(ref target.Field, context);
                // il.EmitWriteLine(string.Format("Clear(ref target.{0});", field.Name));
                il.Emit(OpCodes.Ldarg_0); // target
                if (type.IsClass)
                {
                    il.Emit(OpCodes.Ldind_Ref);
                }

                il.Emit(OpCodes.Ldflda, field); // target.field &
                il.Emit(OpCodes.Ldarg_1);       // context
                var mi = handler.GetType().GetMethod(nameof(SerializationHandler <int> .Clear), BindingFlags.Instance | BindingFlags.Public);
                il.Emit(OpCodes.Call, mi);
            }

            il.Emit(OpCodes.Ret);
        }
Esempio n. 3
0
        public TypeSchema Initialize(KnownSerializers serializers, TypeSchema targetSchema)
        {
            var schema = TypeSchema.FromType(typeof(T), serializers.RuntimeVersion, this.GetType(), Version);

            this.serializeImpl   = Generator.GenerateSerializeMethod <T>(il => Generator.EmitPrimitiveSerialize(typeof(T), il));
            this.deserializeImpl = Generator.GenerateDeserializeMethod <T>(il => Generator.EmitPrimitiveDeserialize(typeof(T), il));
            return(targetSchema ?? schema);
        }
Esempio n. 4
0
 static KnownSerializers()
 {
     UnserializableTypes.Add(typeof(Type));
     UnserializableTypes.Add(typeof(IntPtr));
     UnserializableTypes.Add(typeof(UIntPtr));
     UnserializableTypes.Add(typeof(MemberInfo));
     UnserializableTypes.Add(typeof(System.Diagnostics.StackTrace));
     Default = new KnownSerializers(true, RuntimeInfo.Current);
 }
Esempio n. 5
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);
            }
Esempio n. 6
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);
        }
Esempio n. 7
0
        public TypeSchema Initialize(KnownSerializers serializers, TypeSchema targetSchema)
        {
            var runtimeSchema = TypeSchema.FromType(typeof(T), serializers.RuntimeVersion, this.GetType(), Version);
            var members       = runtimeSchema.GetCompatibleMemberSet(targetSchema);

            this.serializeImpl   = Generator.GenerateSerializeMethod <T>(il => Generator.EmitSerializeFields(typeof(T), serializers, il, members));
            this.deserializeImpl = Generator.GenerateDeserializeMethod <T>(il => Generator.EmitDeserializeFields(typeof(T), serializers, il, members));

            return(targetSchema ?? runtimeSchema);
        }
Esempio n. 8
0
        public TypeSchema Initialize(KnownSerializers serializers, TypeSchema targetSchema)
        {
            if (targetSchema?.Version <= 2)
            {
                // maintain backward compatibility with older serialized data
                this.innerSerializer = new ClassSerializer <MemoryStream>();
            }
            else
            {
                // otherwise default to the new implementation
                this.innerSerializer = new MemoryStreamSerializerImpl();
            }

            return(this.innerSerializer.Initialize(serializers, targetSchema));
        }
Esempio n. 9
0
        // **********************
        // the following methods do the heavy lifting of generating the IL code for each operation we support
        // **********************

        // emits code to clone all the fields (public, private, readonly) that meet the specified criteria
        internal static void EmitCloneFields(Type type, KnownSerializers serializers, ILGenerator il)
        {
            // simply invoke the type serializer for each relevant field
            foreach (FieldInfo field in GetClonableFields(type))
            {
                // argument legend: 0 = source, 1 = ref target, 2 = context
                if (IsSimpleValueType(field.FieldType) || field.FieldType == typeof(string))
                {
                    // for primitive types, simply copy the value from one field to the other
                    il.Emit(OpCodes.Ldarg_1); // target
                    if (type.IsClass)
                    {
                        il.Emit(OpCodes.Ldind_Ref);
                    }

                    il.Emit(OpCodes.Ldarg_0);      // source
                    il.Emit(OpCodes.Ldfld, field); // source.field
                    il.Emit(OpCodes.Stfld, field); // target.field
                }
                else
                {
                    // find the right serializer
                    var handler = serializers.GetUntypedHandler(field.FieldType);
                    int index   = serializers.GetIndex(handler);
                    il.Emit(OpCodes.Ldarg_2);                         // push context
                    il.Emit(OpCodes.Ldc_I4, index);                   // push the serializer id
                    il.Emit(OpCodes.Call, GetHandlerFromIndexMethod); // call GetHandler to push the handler

                    // simply invoke the type serializer for each relevant field
                    il.Emit(OpCodes.Ldarg_0);      // source
                    il.Emit(OpCodes.Ldfld, field); // source.field
                    il.Emit(OpCodes.Ldarg_1);      // target
                    if (type.IsClass)
                    {
                        il.Emit(OpCodes.Ldind_Ref);
                    }

                    il.Emit(OpCodes.Ldflda, field); // target.field &
                    il.Emit(OpCodes.Ldarg_2);       // context

                    // handler.Clone(source.field, target.field, context);
                    var mi = handler.GetType().GetMethod(nameof(SerializationHandler <int> .Clone), BindingFlags.Public | BindingFlags.Instance);
                    il.Emit(OpCodes.Call, mi); // we have the right type, no need for callvirt
                }
            }

            il.Emit(OpCodes.Ret);
        }
Esempio n. 10
0
        // emits code to serialize all the fields (public, private, readonly) that meet the specified criteria
        internal static void EmitSerializeFields(Type type, KnownSerializers serializers, ILGenerator il, IEnumerable <MemberInfo> members = null)
        {
            // enumerate all fields and serialize each of them
            foreach (MemberInfo member in members ?? GetClonableFields(type))
            {
                // inner loop generates this code for each field or property:
                // var handler = GetHandlerFromIndex(index);
                // handler.Serialize(writer, source.fieldOrProp, context);

                // make sure the member is valid
                ValidateMember(type, member);

                // find the right serializer
                var mt      = (member.MemberType == MemberTypes.Field) ? ((FieldInfo)member).FieldType : ((PropertyInfo)member).PropertyType;
                var handler = serializers.GetUntypedHandler(mt);
                int index   = serializers.GetIndex(handler);
                il.Emit(OpCodes.Ldarg_2);                         // push context
                il.Emit(OpCodes.Ldc_I4, index);                   // push the serializer id
                il.Emit(OpCodes.Call, GetHandlerFromIndexMethod); // call GetHandler to push the handler

                // push the arguments
                il.Emit(OpCodes.Ldarg_0); // writer
                il.Emit(OpCodes.Ldarg_1); // source
                if (member.MemberType == MemberTypes.Field)
                {
                    il.Emit(OpCodes.Ldfld, (FieldInfo)member); // source.field
                }
                else
                {
                    var getter = ((PropertyInfo)member).GetGetMethod(true);
                    il.Emit(getter.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, getter);
                }

                il.Emit(OpCodes.Ldarg_2); // context

                // call handler.Serialize(writer, source.field, context)
                var mi = handler.GetType().GetMethod(nameof(SerializationHandler <int> .Serialize), BindingFlags.Instance | BindingFlags.Public);
                il.Emit(OpCodes.Call, mi); // we have the right type, no need for callvirt
            }

            il.Emit(OpCodes.Ret);
        }
Esempio n. 11
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);
            }
Esempio n. 12
0
        // emits code to deserialize all the fields (public, private, readonly) that meet the specified criteria
        internal static void EmitDeserializeFields(Type type, KnownSerializers serializers, ILGenerator il, IEnumerable <MemberInfo> members = null)
        {
            LocalBuilder localBuilder = null;

            // enumerate all fields and deserialize each of them
            foreach (MemberInfo member in members ?? GetClonableFields(type))
            {
                // inner loop generates this code for each field or property:
                // var handler = GetHandlerFromIndex(index);
                // handler.Deserialize(reader, ref target.fieldOrProp, context)

                // make sure the member is valid
                ValidateMember(type, member);

                // find the right serializer first
                var mt      = (member.MemberType == MemberTypes.Field) ? ((FieldInfo)member).FieldType : ((PropertyInfo)member).PropertyType;
                var handler = serializers.GetUntypedHandler(mt);
                int index   = serializers.GetIndex(handler);
                il.Emit(OpCodes.Ldarg_2);                         // push context
                il.Emit(OpCodes.Ldc_I4, index);                   // push the serializer id
                il.Emit(OpCodes.Call, GetHandlerFromIndexMethod); // call GetHandler to push the handler

                // argument legend: 0 = reader, 1 = ref target, 2 = context
                il.Emit(OpCodes.Ldarg_0); // reader
                il.Emit(OpCodes.Ldarg_1); // target&
                if (type.IsClass)
                {
                    il.Emit(OpCodes.Ldind_Ref);
                }

                if (member.MemberType == MemberTypes.Field)
                {
                    il.Emit(OpCodes.Ldflda, (FieldInfo)member); // target.field &
                }
                else
                {
                    var getter = ((PropertyInfo)member).GetGetMethod(true);
                    il.Emit(getter.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, getter);
                    localBuilder = il.DeclareLocal(mt);
                    il.Emit(OpCodes.Stloc, localBuilder);
                    il.Emit(OpCodes.Ldloca, localBuilder);
                }

                il.Emit(OpCodes.Ldarg_2); // context

                // call handler.Deserialize(reader, ref target.field, context)
                var mi = handler.GetType().GetMethod(nameof(SerializationHandler <int> .Deserialize), BindingFlags.Instance | BindingFlags.Public);
                il.Emit(OpCodes.Call, mi); // not callvirt, since we have the right type

                // for properties, call the setter with the result
                if (member.MemberType == MemberTypes.Property)
                {
                    il.Emit(OpCodes.Ldarg_1); // target&
                    if (type.IsClass)
                    {
                        il.Emit(OpCodes.Ldind_Ref);
                    }

                    il.Emit(OpCodes.Ldloc, localBuilder); // deserialization result
                    var setter = ((PropertyInfo)member).GetSetMethod(true);
                    il.Emit(setter.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, setter);
                }
            }

            il.Emit(OpCodes.Ret);
        }
Esempio n. 13
0
 public TypeSchema Initialize(KnownSerializers serializers, TypeSchema targetSchema)
 {
     return(null);
 }
Esempio n. 14
0
 /// <summary>
 /// Initializes a new instance of the <see cref="SerializationContext"/> class, with the specified serialization overrides.
 /// </summary>
 /// <param name="serializers">The set of custom serializers to use instead of the default ones.</param>
 public SerializationContext(KnownSerializers serializers)
 {
     this.serializers = serializers ?? KnownSerializers.Default;
 }
Esempio n. 15
0
 public TypeSchema Initialize(KnownSerializers serializers, TypeSchema targetSchema)
 {
     // schema is not used, since the behavior of arrays is hard-coded
     return(null);
 }
Esempio n. 16
0
        // **********************
        // the following methods do the heavy lifting of generating the IL code for each operation we support
        // **********************

        // emits code to clone all the fields (public, private, readonly) that meet the specified criteria
        internal static void EmitCloneFields(Type type, KnownSerializers serializers, ILGenerator il)
        {
            var cloningFlags = serializers.GetCloningFlags(type);

            // simply invoke the type serializer for each relevant field
            foreach (FieldInfo field in GetAllFields(type))
            {
                // fields with NonSerialized attribute should be skipped if SkipNonSerializedFields is set
                if (field.IsNotSerialized && cloningFlags.HasFlag(CloningFlags.SkipNonSerializedFields))
                {
                    continue;
                }

                // emit exceptions for other non-clonable fields
                else if ((field.FieldType == typeof(IntPtr) || field.FieldType == typeof(UIntPtr)) && !cloningFlags.HasFlag(CloningFlags.CloneIntPtrFields))
                {
                    EmitException(typeof(NotSupportedException), $"Cannot clone field:{field.Name} because cloning of {field.FieldType.Name} fields is disabled by default. To enable cloning of {field.FieldType.Name} fields for the containing type, register the type {type.AssemblyQualifiedName} with the {CloningFlags.CloneIntPtrFields} flag.", il);
                }
                else if (field.FieldType.IsPointer && !cloningFlags.HasFlag(CloningFlags.ClonePointerFields))
                {
                    EmitException(typeof(NotSupportedException), $"Cannot clone field:{field.Name} because cloning of pointer fields is disabled by default. To enable cloning of pointer fields for the containing type, register the type {type.AssemblyQualifiedName} with the {CloningFlags.ClonePointerFields} flag.", il);
                }

                // emit cloning code for clonable fields
                // argument legend: 0 = source, 1 = ref target, 2 = context
                else if (IsSimpleValueType(field.FieldType) || field.FieldType == typeof(string) || field.FieldType.IsPointer)
                {
                    // for primitive types, simply copy the value from one field to the other
                    il.Emit(OpCodes.Ldarg_1); // target
                    if (type.IsClass)
                    {
                        il.Emit(OpCodes.Ldind_Ref);
                    }

                    il.Emit(OpCodes.Ldarg_0);      // source
                    il.Emit(OpCodes.Ldfld, field); // source.field
                    il.Emit(OpCodes.Stfld, field); // target.field
                }
                else
                {
                    // find the right serializer
                    var handler = serializers.GetUntypedHandler(field.FieldType);
                    int index   = serializers.GetIndex(handler);
                    il.Emit(OpCodes.Ldarg_2);                         // push context
                    il.Emit(OpCodes.Ldc_I4, index);                   // push the serializer id
                    il.Emit(OpCodes.Call, GetHandlerFromIndexMethod); // call GetHandler to push the handler

                    // simply invoke the type serializer for each relevant field
                    il.Emit(OpCodes.Ldarg_0);      // source
                    il.Emit(OpCodes.Ldfld, field); // source.field
                    il.Emit(OpCodes.Ldarg_1);      // target
                    if (type.IsClass)
                    {
                        il.Emit(OpCodes.Ldind_Ref);
                    }

                    il.Emit(OpCodes.Ldflda, field); // target.field &
                    il.Emit(OpCodes.Ldarg_2);       // context

                    // handler.Clone(source.field, target.field, context);
                    var mi = handler.GetType().GetMethod(nameof(SerializationHandler <int> .Clone), BindingFlags.Public | BindingFlags.Instance);
                    il.Emit(OpCodes.Call, mi); // we have the right type, no need for callvirt
                }
            }

            il.Emit(OpCodes.Ret);
        }
Esempio n. 17
0
 public TypeSchema Initialize(KnownSerializers serializers, TypeSchema targetSchema)
 {
     return(targetSchema ?? TypeSchema.FromType(typeof(string), serializers.RuntimeVersion, this.GetType(), Version));
 }