static void WriteSerializerDictionary(TypeBuilder typeBuilder, ILGenerator il, Type type, MethodInfo getValueMethod, int?valueLocalIndex = null, OpCode?valueLocalOpCode = null) { var keyType = typeof(object); var valueType = typeof(object); if (type.ContainsGenericParameters) { var arguments = type.GetGenericArguments(); keyType = arguments[0]; valueType = arguments[1]; } else { // Custom IDictionary implementation var interfaces = type.GetInterfaces(); for (int i = 0; i < interfaces.Length; i++) { var @interface = interfaces[i]; if (@interface.IsGenericType && @interface.GetGenericTypeDefinition() == GenericIDictType) { var arguments = @interface.GetGenericArguments(); keyType = arguments[0]; valueType = arguments[1]; break; } } } var keyValuePairType = GenericKeyValuePairType.MakeGenericType(keyType, valueType); var enumeratorType = GenericDictionaryEnumerator.MakeGenericType(keyType, valueType); var enumeratorLocal = il.DeclareLocal(enumeratorType); var entryLocal = il.DeclareLocal(keyValuePairType); var startEnumeratorLabel = il.DefineLabel(); var moveNextLabel = il.DefineLabel(); var endEnumeratorLabel = il.DefineLabel(); if (valueLocalIndex != null) { il.Emit(valueLocalOpCode.Value, valueLocalIndex.Value); } if (getValueMethod != null) { if (valueLocalIndex == null) { il.Emit(OpCodes.Ldarg_2); } il.Emit(OpCodes.Callvirt, getValueMethod); } if (type.ContainsGenericParameters) { il.Emit(OpCodes.Callvirt, GenericDictType.MakeGenericType(keyType, valueType).GetMethod("GetEnumerator")); } else { il.Emit(OpCodes.Callvirt, type.GetMethod("GetEnumerator")); } il.Emit(OpCodes.Stloc_S, enumeratorLocal.LocalIndex); il.BeginExceptionBlock(); il.Emit(OpCodes.Br, startEnumeratorLabel); il.MarkLabel(moveNextLabel); il.Emit(OpCodes.Ldloca_S, enumeratorLocal.LocalIndex); il.Emit(OpCodes.Call, enumeratorLocal.LocalType.GetProperty("Current") .GetGetMethod()); il.Emit(OpCodes.Stloc, entryLocal.LocalIndex); if (keyType.IsComplexType()) { var keyMethod = keyValuePairType.GetProperty("Key").GetGetMethod(); if (keyType.IsCollectionType()) { WriteSerializerClass(typeBuilder, il, keyType, 1, keyMethod, callerType: keyType, valueLocalIndex: entryLocal.LocalIndex, valueLocalOpCode: OpCodes.Ldloca_S); } else { WriteSerializerCallClassMethod(typeBuilder, il, keyType, OpCodes.Ldloca_S, entryLocal.LocalIndex, 1, keyMethod, needClassHeader: false); } } else { var keyMethod = keyValuePairType.GetProperty("Key").GetGetMethod(); WriteSerializerBytesToStream(il, keyType, OpCodes.Ldloca_S, entryLocal.LocalIndex, 1, keyMethod, isTargetCollection: true); } if (valueType.IsComplexType()) { var valueMethod = keyValuePairType.GetProperty("Value").GetGetMethod(); if (valueType.IsCollectionType()) { WriteSerializerClass(typeBuilder, il, valueType, 2, valueMethod, callerType: valueType, valueLocalIndex: entryLocal.LocalIndex, valueLocalOpCode: OpCodes.Ldloca_S); } else { WriteSerializerCallClassMethod(typeBuilder, il, valueType, OpCodes.Ldloca_S, entryLocal.LocalIndex, 2, valueMethod, needClassHeader: false); } } else { var valueMethod = keyValuePairType.GetProperty("Value").GetGetMethod(); WriteSerializerBytesToStream(il, valueType, OpCodes.Ldloca_S, entryLocal.LocalIndex, 2, valueMethod, isTargetCollection: true); } il.MarkLabel(startEnumeratorLabel); il.Emit(OpCodes.Ldloca_S, enumeratorLocal.LocalIndex); il.Emit(OpCodes.Call, enumeratorType.GetMethod("MoveNext", MethodBinding)); il.Emit(OpCodes.Brtrue, moveNextLabel); il.Emit(OpCodes.Leave, endEnumeratorLabel); il.BeginFinallyBlock(); il.Emit(OpCodes.Ldloca_S, enumeratorLocal.LocalIndex); il.Emit(OpCodes.Constrained, enumeratorLocal.LocalType); il.Emit(OpCodes.Callvirt, IDisposableDisposeMethod); il.EndExceptionBlock(); il.MarkLabel(endEnumeratorLabel); }
static void WriteDeserializerDictionary(TypeBuilder typeBuilder, ILGenerator il, Type type, int tag, MethodInfo setMethod, int?itemLocalIndex = null) { var keyType = typeof(object); var valueType = typeof(object); if (type.ContainsGenericParameters) { var arguments = type.GetGenericArguments(); keyType = arguments[0]; valueType = arguments[1]; if (GenericIDictType.IsAssignableFrom(type.GetGenericTypeDefinition())) { type = GenericDictType.MakeGenericType(keyType, valueType); } } else { // Custom IDictionary implementation var interfaces = type.GetInterfaces(); for (int i = 0; i < interfaces.Length; i++) { var @interface = interfaces[i]; if (@interface.IsGenericType && @interface.GetGenericTypeDefinition() == GenericIDictType) { var arguments = @interface.GetGenericArguments(); keyType = arguments[0]; valueType = arguments[1]; break; } } } var lengthLocal = il.DeclareLocal(typeof(int)); var dictLocal = il.DeclareLocal(type); var keyItemLocal = il.DeclareLocal(keyType); var valueItemLocal = il.DeclareLocal(valueType); var indexLocal = il.DeclareLocal(typeof(int)); var startLabel = il.DefineLabel(); var endLabel = il.DefineLabel(); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldarg_3); il.Emit(OpCodes.Ldc_I4, tag); il.Emit(OpCodes.Call, GetCollectionLengthMethod); il.Emit(OpCodes.Stloc, lengthLocal); il.Emit(OpCodes.Ldloc, lengthLocal.LocalIndex); il.Emit(OpCodes.Newobj, type.GetConstructor(CtorCapacityTypes)); il.Emit(OpCodes.Stloc, dictLocal.LocalIndex); il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Stloc, indexLocal.LocalIndex); il.Emit(OpCodes.Br, startLabel); il.MarkLabel(endLabel); WriteDeserializerReadValue(typeBuilder, il, keyType, 1, keyItemLocal.LocalIndex); WriteDeserializerReadValue(typeBuilder, il, valueType, 2, valueItemLocal.LocalIndex); il.Emit(OpCodes.Ldloc, dictLocal.LocalIndex); il.Emit(OpCodes.Ldloc, keyItemLocal.LocalIndex); il.Emit(OpCodes.Ldloc, valueItemLocal.LocalIndex); il.Emit(OpCodes.Callvirt, type.GetMethod("set_Item")); il.Emit(OpCodes.Ldloc, indexLocal.LocalIndex); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.Add); il.Emit(OpCodes.Stloc, indexLocal.LocalIndex); il.MarkLabel(startLabel); il.Emit(OpCodes.Ldloc, indexLocal.LocalIndex); il.Emit(OpCodes.Ldloc, lengthLocal.LocalIndex); il.Emit(OpCodes.Blt, endLabel); if (itemLocalIndex == null) { il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldloc, dictLocal.LocalIndex); il.Emit(OpCodes.Callvirt, setMethod); } else { il.Emit(OpCodes.Ldloc, dictLocal.LocalIndex); il.Emit(OpCodes.Stloc, itemLocalIndex.Value); } }