private static IFormatter CreateGenericFormatter(Type formattedType, ModuleBuilder moduleBuilder, ISerializationPolicy policy)
        {
            Dictionary <string, MemberInfo> serializableMembers = FormatterUtilities.GetSerializableMembersMap(formattedType, policy);

            if (serializableMembers.Count == 0)
            {
                return((IFormatter)Activator.CreateInstance(typeof(EmptyTypeFormatter <>).MakeGenericType(formattedType)));
            }

            string helperTypeName = moduleBuilder.Name + "." + formattedType.GetCompilableNiceFullName() + "___" + formattedType.Assembly.GetName().Name + "___FormatterHelper___" + Guid.NewGuid().ToString();

            Dictionary <Type, MethodInfo>   serializerReadMethods;
            Dictionary <Type, MethodInfo>   serializerWriteMethods;
            Dictionary <Type, FieldBuilder> serializerFields;
            FieldBuilder dictField;
            Dictionary <MemberInfo, List <string> > memberNames;

            BuildHelperType(
                moduleBuilder,
                helperTypeName,
                formattedType,
                serializableMembers,
                out serializerReadMethods,
                out serializerWriteMethods,
                out serializerFields,
                out dictField,
                out memberNames
                );

            Type     formatterType = typeof(RuntimeEmittedFormatter <>).MakeGenericType(formattedType);
            Delegate del1, del2;

            // Read
            {
                Type          readDelegateType    = typeof(ReadDataEntryMethodDelegate <>).MakeGenericType(formattedType);
                MethodInfo    readDataEntryMethod = formatterType.GetMethod("ReadDataEntry", Flags.InstanceAnyVisibility);
                DynamicMethod dynamicReadMethod   = new DynamicMethod("Dynamic_" + formattedType.GetCompilableNiceFullName(), null, readDataEntryMethod.GetParameters().Select(n => n.ParameterType).ToArray(), true);
                readDataEntryMethod.GetParameters().ForEach(n => dynamicReadMethod.DefineParameter(n.Position, n.Attributes, n.Name));
                EmitReadMethodContents(dynamicReadMethod.GetILGenerator(), formattedType, dictField, serializerFields, memberNames, serializerReadMethods);
                del1 = dynamicReadMethod.CreateDelegate(readDelegateType);
            }

            // Write
            {
                Type          writeDelegateType      = typeof(WriteDataEntriesMethodDelegate <>).MakeGenericType(formattedType);
                MethodInfo    writeDataEntriesMethod = formatterType.GetMethod("WriteDataEntries", Flags.InstanceAnyVisibility);
                DynamicMethod dynamicWriteMethod     = new DynamicMethod("Dynamic_Write_" + formattedType.GetCompilableNiceFullName(), null, writeDataEntriesMethod.GetParameters().Select(n => n.ParameterType).ToArray(), true);
                writeDataEntriesMethod.GetParameters().ForEach(n => dynamicWriteMethod.DefineParameter(n.Position + 1, n.Attributes, n.Name));
                EmitWriteMethodContents(dynamicWriteMethod.GetILGenerator(), formattedType, serializerFields, memberNames, serializerWriteMethods);
                del2 = dynamicWriteMethod.CreateDelegate(writeDelegateType);
            }

            return((IFormatter)Activator.CreateInstance(formatterType, del1, del2));
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Provides the actual implementation for deserializing a value of type <see cref="T" />.
        /// </summary>
        /// <param name="value">The uninitialized value to serialize into. This value will have been created earlier using <see cref="BaseFormatter{T}.GetUninitializedObject" />.</param>
        /// <param name="reader">The reader to deserialize with.</param>
        protected override void DeserializeImplementation(ref T value, IDataReader reader)
        {
            // We sadly *must* box so that complex value types get their values properly set by reflection.
            // At least we only box these once.
            object boxedValue = value;

            var members = FormatterUtilities.GetSerializableMembersMap(typeof(T), this.OverridePolicy ?? reader.Context.Config.SerializationPolicy);

            EntryType entryType;
            string    name;

            while ((entryType = reader.PeekEntry(out name)) != EntryType.EndOfNode && entryType != EntryType.EndOfArray && entryType != EntryType.EndOfStream)
            {
                if (string.IsNullOrEmpty(name))
                {
                    reader.Context.Config.DebugContext.LogError("Entry of type \"" + entryType + "\" in node \"" + reader.CurrentNodeName + "\" is missing a name.");
                    reader.SkipEntry();
                    continue;
                }

                MemberInfo member;

                if (members.TryGetValue(name, out member) == false)
                {
                    reader.Context.Config.DebugContext.LogWarning("Lost serialization data for entry \"" + name + "\" of type \"" + entryType + "\"in node \"" + reader.CurrentNodeName + "\".");
                    reader.SkipEntry();
                    continue;
                }

                Type expectedType = FormatterUtilities.GetContainedType(member);

                try
                {
                    var    serializer = Serializer.Get(expectedType);
                    object entryValue = serializer.ReadValueWeak(reader);
                    FormatterUtilities.SetMemberValue(member, boxedValue, entryValue);
                }
                catch (Exception ex)
                {
                    reader.Context.Config.DebugContext.LogException(ex);
                }
            }

            value = (T)boxedValue; // Unbox
        }
        /// <summary>
        /// Emits a formatter for a given type into a given module builder, using a given serialization policy to determine which members to serialize.
        /// </summary>
        /// <param name="formattedType">Type to create a formatter for.</param>
        /// <param name="moduleBuilder">The module builder to emit a formatter into.</param>
        /// <param name="policy">The serialization policy to use for creating the formatter.</param>
        /// <returns>The fully constructed, emitted formatter type.</returns>
        public static Type EmitAOTFormatter(Type formattedType, ModuleBuilder moduleBuilder, ISerializationPolicy policy)
        {
            Dictionary <string, MemberInfo> serializableMembers = FormatterUtilities.GetSerializableMembersMap(formattedType, policy);

            string formatterName       = moduleBuilder.Name + "." + formattedType.GetCompilableNiceFullName() + "__AOTFormatter";
            string formatterHelperName = moduleBuilder.Name + "." + formattedType.GetCompilableNiceFullName() + "__FormatterHelper";

            if (serializableMembers.Count == 0)
            {
                return(moduleBuilder.DefineType(
                           formatterName,
                           TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Class,
                           typeof(EmptyAOTEmittedFormatter <>).MakeGenericType(formattedType)
                           ).CreateType());
            }

            Dictionary <Type, MethodInfo>   serializerReadMethods;
            Dictionary <Type, MethodInfo>   serializerWriteMethods;
            Dictionary <Type, FieldBuilder> serializerFields;
            FieldBuilder dictField;
            Dictionary <MemberInfo, List <string> > memberNames;

            BuildHelperType(
                moduleBuilder,
                formatterHelperName,
                formattedType,
                serializableMembers,
                out serializerReadMethods,
                out serializerWriteMethods,
                out serializerFields,
                out dictField,
                out memberNames
                );

            TypeBuilder formatterType = moduleBuilder.DefineType(
                formatterName,
                TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Class,
                typeof(AOTEmittedFormatter <>).MakeGenericType(formattedType)
                );

            // Read
            {
                MethodInfo readBaseMethod = formatterType.BaseType.GetMethod("ReadDataEntry", Flags.InstanceAnyVisibility);

                MethodBuilder readMethod = formatterType.DefineMethod(
                    readBaseMethod.Name,
                    MethodAttributes.Family | MethodAttributes.Virtual,
                    readBaseMethod.ReturnType,
                    readBaseMethod.GetParameters().Select(n => n.ParameterType).ToArray()
                    );

                readBaseMethod.GetParameters().ForEach(n => readMethod.DefineParameter(n.Position, n.Attributes, n.Name));
                EmitReadMethodContents(readMethod.GetILGenerator(), formattedType, dictField, serializerFields, memberNames, serializerReadMethods);
            }

            // Write
            {
                MethodInfo writeBaseMethod = formatterType.BaseType.GetMethod("WriteDataEntries", Flags.InstanceAnyVisibility);

                MethodBuilder dynamicWriteMethod = formatterType.DefineMethod(
                    writeBaseMethod.Name,
                    MethodAttributes.Family | MethodAttributes.Virtual,
                    writeBaseMethod.ReturnType,
                    writeBaseMethod.GetParameters().Select(n => n.ParameterType).ToArray()
                    );

                writeBaseMethod.GetParameters().ForEach(n => dynamicWriteMethod.DefineParameter(n.Position + 1, n.Attributes, n.Name));
                EmitWriteMethodContents(dynamicWriteMethod.GetILGenerator(), formattedType, serializerFields, memberNames, serializerWriteMethods);
            }

            var result = formatterType.CreateType();

            // Register the formatter on the assembly
            ((AssemblyBuilder)moduleBuilder.Assembly).SetCustomAttribute(new CustomAttributeBuilder(typeof(RegisterFormatterAttribute).GetConstructor(new Type[] { typeof(Type), typeof(int) }), new object[] { formatterType, -1 }));

            return(result);
        }