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___" + System.Threading.Interlocked.Increment(ref helperFormatterNameId); 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)); }
/// <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); }