/// <summary> /// Provides the actual implementation for serializing a value of type <see cref="T" />. /// </summary> /// <param name="value">The value to serialize.</param> /// <param name="writer">The writer to serialize with.</param> protected override void SerializeImplementation(ref T value, IDataWriter writer) { var members = FormatterUtilities.GetSerializableMembers(typeof(T), this.OverridePolicy ?? writer.Context.Config.SerializationPolicy); for (int i = 0; i < members.Length; i++) { var member = members[i]; Type type; var memberValue = FormatterUtilities.GetMemberValue(member, value); if (object.ReferenceEquals(memberValue, null)) { type = FormatterUtilities.GetContainedType(member); } else { type = memberValue.GetType(); } var serializer = Serializer.Get(type); try { serializer.WriteValueWeak(member.Name, memberValue, writer); } catch (Exception ex) { writer.Context.Config.DebugContext.LogException(ex); } } }
private static IFormatter CreateGenericFormatter(Type formattedType, ModuleBuilder moduleBuilder, ISerializationPolicy policy) { MemberInfo[] members = FormatterUtilities.GetSerializableMembers(formattedType, 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, members, serializerFields, memberNames, serializerWriteMethods); del2 = dynamicWriteMethod.CreateDelegate(writeDelegateType); } return((IFormatter)Activator.CreateInstance(formatterType, del1, del2)); }
/// <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) { MemberInfo[] members = FormatterUtilities.GetSerializableMembers(formattedType, 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, members, 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); }
private static void ReplaceAllReferencesInGraph(object graph, object oldReference, object newReference, HashSet <object> processedReferences = null) { if (processedReferences == null) { processedReferences = new HashSet <object>(ReferenceEqualityComparer <object> .Default); } processedReferences.Add(graph); if (graph.GetType().IsArray) { Array array = (Array)graph; for (int i = 0; i < array.Length; i++) { var value = array.GetValue(i); if (object.ReferenceEquals(value, null)) { continue; } if (object.ReferenceEquals(value, oldReference)) { array.SetValue(newReference, i); value = newReference; } if (!processedReferences.Contains(value)) { ReplaceAllReferencesInGraph(value, oldReference, newReference, processedReferences); } } } else { var members = FormatterUtilities.GetSerializableMembers(graph.GetType(), SerializationPolicies.Everything); for (int i = 0; i < members.Length; i++) { FieldInfo field = (FieldInfo)members[i]; if (field.FieldType.IsPrimitive || field.FieldType == typeof(SerializationData) || field.FieldType == typeof(string)) { continue; } object value = field.GetValue(graph); if (object.ReferenceEquals(value, null)) { continue; } Type valueType = value.GetType(); if (valueType.IsPrimitive || valueType == typeof(SerializationData) || valueType == typeof(string)) { continue; } if (object.ReferenceEquals(value, oldReference)) { field.SetValue(graph, newReference); value = newReference; } if (!processedReferences.Contains(value)) { ReplaceAllReferencesInGraph(value, oldReference, newReference, processedReferences); } } } }