private static DeserializationFunc <T> CreateUnionDeserializationFunc <T>(Type[] types) { var deserialzationFunc = new DynamicMethod(string.Empty, typeof(T), new[] { typeof(byte[]), typeof(int), typeof(int), typeof(int), typeof(int), typeof(int).MakeByRefType() }, true); var il = deserialzationFunc.GetILGenerator(); var index = il.DeclareLocal(typeof(int)); var indexSize = il.DeclareLocal(typeof(int)); var objectSize = il.DeclareLocal(typeof(int)); var result = il.DeclareLocal(typeof(T)); il.EmitLoadArgument(0); il.EmitLoadArgument(1); il.EmitLoadArgument(2); il.EmitLoadLocalAddress(indexSize.LocalIndex); il.Emit(OpCodes.Call, typeof(Binary).GetMethod(nameof(Binary.InternalRead7BitEncodedInt32), BindingFlagsEx.Static)); il.EmitStoreLocal(index.LocalIndex); { var validIndex = il.DefineLabel(); il.EmitLoadLocal(index.LocalIndex); il.EmitLoadDeclaredConstant(types.Length); il.Emit(OpCodes.Ble_S, validIndex); il.Emit(OpCodes.Ldstr, "Failed to deserialize the object, because its union index was out of bounds."); il.Emit(OpCodes.Newobj, typeof(SerializationException).GetConstructor(new[] { typeof(string) })); il.Emit(OpCodes.Throw); il.MarkLabel(validIndex); } { var valueNotNull = il.DefineLabel(); il.EmitLoadLocal(result.LocalIndex); il.Emit(OpCodes.Brtrue_S, valueNotNull); il.EmitLoadArgument(5); il.EmitLoadLocal(indexSize.LocalIndex); il.Emit(OpCodes.Stind_I4); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Ret); il.MarkLabel(valueNotNull); } il.EmitLoadArgument(1); il.EmitLoadLocal(indexSize.LocalIndex); il.Emit(OpCodes.Add); il.EmitStoreArgument(1); il.EmitLoadArgument(2); il.EmitLoadLocal(indexSize.LocalIndex); il.Emit(OpCodes.Sub); il.EmitStoreArgument(2); il.EmitLoadLocal(index.LocalIndex); il.EmitLoadDeclaredConstant(1); il.Emit(OpCodes.Sub); il.EmitStoreLocal(index.LocalIndex); var jumpTable = new Label[types.Length]; var endOfSwitch = il.DefineLabel(); for (var i = 0; i < types.Length; i++) { jumpTable[i] = il.DefineLabel(); } il.EmitLoadLocal(index.LocalIndex); il.Emit(OpCodes.Switch, jumpTable); for (var i = 0; i < types.Length; i++) { var type = types[i]; il.MarkLabel(jumpTable[i]); GenericFormatter.EmitLoadCachedInstance(il, type); il.EmitLoadArgument(0); il.EmitLoadArgument(1); il.EmitLoadArgument(2); il.EmitLoadArgument(3); il.EmitLoadArgument(4); il.EmitLoadLocalAddress(objectSize.LocalIndex); GenericFormatter.EmitDeserialize(il, type); if (type.IsValueType) { il.Emit(OpCodes.Box, type); } il.EmitStoreLocal(result.LocalIndex); il.Emit(OpCodes.Br, endOfSwitch); } il.MarkLabel(endOfSwitch); il.EmitLoadArgument(5); il.EmitLoadLocal(indexSize.LocalIndex); il.EmitLoadLocal(objectSize.LocalIndex); il.Emit(OpCodes.Add); il.Emit(OpCodes.Stind_I4); il.EmitLoadLocal(result.LocalIndex); il.Emit(OpCodes.Ret); return((DeserializationFunc <T>)deserialzationFunc.CreateDelegate(typeof(DeserializationFunc <T>))); }
private static void DeserializeField(ILGenerator il, FieldInfo field, LocalBuilder size) { var type = PrimitiveTypes.GetPrimitiveType(field.FieldType); if (type == PrimitiveType.NotPrimitive) { GenericFormatter.EmitLoadCachedInstance(il, field.FieldType); } il.EmitLoadArgument(0); il.EmitLoadArgument(1); il.EmitLoadArgument(2); il.EmitLoadLocalAddress(size.LocalIndex); switch (type) { case PrimitiveType.NotPrimitive: il.EmitLoadArgument(4); il.EmitLoadArgument(5); GenericFormatter.EmitDeserialize(il, field.FieldType); break; case PrimitiveType.SByte: il.Emit(OpCodes.Call, typeof(Binary).GetMethod(nameof(Binary.InternalReadSByte), BindingFlagsEx.Static)); break; case PrimitiveType.Byte: il.Emit(OpCodes.Call, typeof(Binary).GetMethod(nameof(Binary.InternalReadByte), BindingFlagsEx.Static)); break; case PrimitiveType.Int16: il.Emit(OpCodes.Call, typeof(Binary).GetMethod(nameof(Binary.InternalReadInt16), BindingFlagsEx.Static)); break; case PrimitiveType.UInt16: il.Emit(OpCodes.Call, typeof(Binary).GetMethod(nameof(Binary.InternalReadUInt16), BindingFlagsEx.Static)); break; case PrimitiveType.Int32: il.Emit(OpCodes.Call, typeof(Binary).GetMethod(nameof(Binary.InternalRead7BitEncodedInt32), BindingFlagsEx.Static)); break; case PrimitiveType.UInt32: il.Emit(OpCodes.Call, typeof(Binary).GetMethod(nameof(Binary.InternalRead7BitEncodedUInt32), BindingFlagsEx.Static)); break; case PrimitiveType.Int64: il.Emit(OpCodes.Call, typeof(Binary).GetMethod(nameof(Binary.InternalRead7BitEncodedInt64), BindingFlagsEx.Static)); break; case PrimitiveType.UInt64: il.Emit(OpCodes.Call, typeof(Binary).GetMethod(nameof(Binary.InternalRead7BitEncodedUInt64), BindingFlagsEx.Static)); break; case PrimitiveType.Boolean: il.Emit(OpCodes.Call, typeof(Binary).GetMethod(nameof(Binary.InternalReadBoolean), BindingFlagsEx.Static)); break; case PrimitiveType.Char: il.Emit(OpCodes.Call, typeof(Binary).GetMethod(nameof(Binary.InternalReadChar), BindingFlagsEx.Static)); break; case PrimitiveType.Single: il.Emit(OpCodes.Call, typeof(Binary).GetMethod(nameof(Binary.InternalReadSingle), BindingFlagsEx.Static)); break; case PrimitiveType.Double: il.Emit(OpCodes.Call, typeof(Binary).GetMethod(nameof(Binary.InternalReadDouble), BindingFlagsEx.Static)); break; default: Debug.Assert(false); break; } }