Пример #1
0
        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);
            }
        }