Ejemplo n.º 1
0
		public void Emit(FieldInfo field, ref EmitHelper serializerEmit, ref EmitHelper deserializeEmit)
		{
			var writeIntMethod = typeof(BinaryWriter).GetMethod("Write", new[] { typeof(int) });
			var writeStringMethod = typeof(BinaryWriter).GetMethod("Write", new[] { typeof(string) });
			var arrayNotNullLabel = serializerEmit.DefineLabel();
			var arrayNullLabel = serializerEmit.DefineLabel();
			var whileLabel = serializerEmit.DefineLabel();
			var endWhileLabel = serializerEmit.DefineLabel();
			var elementType = field.FieldType.GetElementType();
			var iLocal = serializerEmit.DeclareLocal(typeof(int));
			var lenLocal = serializerEmit.DeclareLocal(typeof(int));
			serializerEmit
				.ldarg_0
				.ldfld(field)
				.brtrue(arrayNotNullLabel)
				.ldarg_1
				.ldc_i4_m1
				.call(writeIntMethod)
				.br(arrayNullLabel);
			serializerEmit
				.MarkLabel(arrayNotNullLabel)
				.ldc_i4_0
				.stloc(iLocal)
				.ldarg_0
				.ldfld(field)
				.ldlen
				.conv_i4
				.stloc(lenLocal)
				.ldarg_1
				.ldloc(lenLocal)
				.call(writeIntMethod)
				.br(endWhileLabel)
				.MarkLabel(whileLabel);
			#region string
			if (elementType == typeof(string))
			{
				var strElement = serializerEmit.DeclareLocal(typeof(string));
				var strElementNullLbl = serializerEmit.DefineLabel();
				var strElementNotNullLbl = serializerEmit.DefineLabel();
				serializerEmit
					.ldarg_0
					.ldfld(field)
					.ldloc(iLocal)
					.ldelem_ref
					.stloc(strElement)
					.ldloc(strElement)
					.brtrue(strElementNotNullLbl)
					.ldarg_1
					.ldc_i4_m1
					.call(writeIntMethod)
					.br(strElementNullLbl)
					.MarkLabel(strElementNotNullLbl)
					.ldarg_1
					.ldloc(strElement)
					.call(typeof(string).GetMethod("get_Length"))
					.call(writeIntMethod)
					.ldarg_1
					.ldloc(strElement)
					.call(writeStringMethod)
					.MarkLabel(strElementNullLbl)
					.ldloc(iLocal)
					.ldc_i4_1
					.add
					.stloc(iLocal);
			}
			#endregion

			#region Primitive, DateTime, decimal
			else if (elementType.IsPrimitive || elementType == typeof(DateTime) || elementType == typeof(decimal))
			{
				serializerEmit
					.ldarg_1
					.ldarg_0
					.ldfld(field)
					.ldloc(iLocal)
					.dup
					.ldc_i4_1
					.add
					.stloc(iLocal);
				if (elementType == typeof(bool) || elementType == typeof(sbyte))
				{
					serializerEmit = serializerEmit.ldelem_i1;
				}
				else if (elementType == typeof(byte))
				{
					serializerEmit = serializerEmit.ldelem_u1;
				}
				else if (elementType == typeof(char) || elementType == typeof(ushort))
				{
					serializerEmit = serializerEmit.ldelem_u2;
				}
				else if (elementType == typeof(short))
				{
					serializerEmit = serializerEmit.ldelem_i2;
				}
				else if (elementType == typeof(int))
				{
					serializerEmit = serializerEmit.ldelem_i4;
				}
				else if (elementType == typeof(uint))
				{
					serializerEmit = serializerEmit.ldelem_u4;
				}
				else if (elementType == typeof(float))
				{
					serializerEmit = serializerEmit.ldelem_r4;
				}
				else if (elementType == typeof(long) || elementType == typeof(ulong))
				{
					serializerEmit = serializerEmit.ldelem_i8;
				}
				else if (elementType == typeof(double))
				{
					serializerEmit = serializerEmit.ldelem_r8;
				}
				else if (elementType == typeof(decimal))
				{
					serializerEmit = serializerEmit.ldelema(elementType).ldobj(elementType);
				}
				else if (elementType == typeof(DateTime))
				{
					serializerEmit = serializerEmit.ldelema(elementType).call(typeof(DateTime).GetMethod("get_Ticks"));
				}
				var writeElementType = elementType != typeof(DateTime) ? elementType : typeof(long);
				serializerEmit
					.call(typeof(BinaryWriter).GetMethod("Write", new[] { writeElementType }));
			}
			#endregion

			#region object
			else if (elementType.IsClass)
			{
				var obj = serializerEmit.DeclareLocal(typeof(object));
				var elementNullLabel = serializerEmit.DefineLabel();
				var elementNotNullLabel = serializerEmit.DefineLabel();
				var objectExistsLocal = serializerEmit.DefineLabel();
				var objectNotExistsLocal = serializerEmit.DefineLabel();
				serializerEmit
					.ldarg_0
					.ldfld(field)
					.ldloc(iLocal)
					.ldelem_ref
					.stloc(obj)
					.ldloc(obj)
					.brtrue(elementNotNullLabel)
					.ldarg_1
					.ldc_i4_m1
					.call(typeof(BinaryWriter).GetMethod("Write", new[] { typeof(int) }))
					.br(elementNullLabel)
					.MarkLabel(elementNotNullLabel)
					.ldarg_2
					.ldloc(obj)
					.call(typeof(IDictionary<object, int>).GetMethod("ContainsKey", new[] { typeof(object) }))
					.brtrue(objectExistsLocal)
					.ldarg_1
					.ldarg_3
					.call(typeof(BinaryWriter).GetMethod("Write", new[] { typeof(int) }))
					.ldloc(obj)
					.castclass(typeof(ISerializable))
					.ldarg_1
					.ldarg_2
					.ldarg_3
					.call(typeof(ISerializable).GetMethod("Serialize"))
					.br(objectNotExistsLocal)
					.MarkLabel(objectExistsLocal)
					.ldarg_1
					.ldarg_2
					.ldloc(obj)
					.call(typeof(IDictionary<object, int>).GetMethod("get_Item", new[] { typeof(object) }))
					.call(typeof(BinaryWriter).GetMethod("Write", new[] { typeof(int) }))
					.MarkLabel(objectNotExistsLocal)
					.MarkLabel(elementNullLabel)
					.ldloc(iLocal)
					.ldc_i4_1
					.add
					.stloc(iLocal);
			}
			#endregion

			serializerEmit
				.MarkLabel(endWhileLabel)
				.ldloc(iLocal)
				.ldloc(lenLocal)
				.blt(whileLabel)
				.MarkLabel(arrayNullLabel);

			var readIntMethod = typeof(BinaryReader).GetMethod("ReadInt32");
			var arrayNotNullLabel2 = deserializeEmit.DefineLabel();
			var arrayNullLabel2 = deserializeEmit.DefineLabel();
			var arrayLocal = deserializeEmit.DeclareLocal(field.FieldType);
			var len = deserializeEmit.DeclareLocal(typeof(int));
			var i = deserializeEmit.DeclareLocal(typeof(int));
			var beginForLabel = deserializeEmit.DefineLabel();
			var beginForBodyLabel = deserializeEmit.DefineLabel();
			deserializeEmit = deserializeEmit
				.ldarg_1
				.call(readIntMethod)
				.stloc(len)
				.ldloc(len)
				.ldc_i4_m1
				.ceq
				.brfalse(arrayNotNullLabel2)
				.ldarg_0
				.ldnull
				.stfld(field)
				.br(arrayNullLabel2)
				.MarkLabel(arrayNotNullLabel2)
				.ldloc(len)
				.newarr(elementType)
				.stloc(arrayLocal)
				.ldc_i4_0
				.stloc(i)
				.br(beginForLabel)
				.MarkLabel(beginForBodyLabel);
			#region Primitive, decimal, DateTime
			if (elementType.IsPrimitive)
			{
				deserializeEmit
					.ldloc(arrayLocal)
					.ldloc(i)
					.ldarg_1
					.call(typeof(BinaryReader).GetMethod("Read" + elementType.Name));
				if (elementType == typeof(bool) || elementType == typeof(sbyte) || elementType == typeof(byte))
				{
					deserializeEmit = deserializeEmit.stelem_i1;
				}
				else if (elementType == typeof(char) || elementType == typeof(ushort) || elementType == typeof(short))
				{
					deserializeEmit = deserializeEmit.stelem_i2;
				}
				else if (elementType == typeof(int) || elementType == typeof(uint))
				{
					deserializeEmit = deserializeEmit.stelem_i4;
				}
				else if (elementType == typeof(float))
				{
					deserializeEmit = deserializeEmit.stelem_r4;
				}
				else if (elementType == typeof(long) || elementType == typeof(ulong))
				{
					deserializeEmit = deserializeEmit.stelem_i8;
				}
				else if (elementType == typeof(double))
				{
					deserializeEmit = deserializeEmit.stelem_r8;
				}
			}
			else if (elementType == typeof(decimal))
			{
				deserializeEmit
					.ldloc(arrayLocal)
					.ldloc(i)
					.ldelema(typeof(decimal))
					.ldarg_1
					.call(typeof(BinaryReader).GetMethod("ReadDecimal"))
					.stobj(typeof(decimal));
			}
			else if (elementType == typeof(DateTime))
			{
				deserializeEmit
					.ldloc(arrayLocal)
					.ldloc(i)
					.ldelema(typeof(DateTime))
					.ldarg_1
					.call(typeof(BinaryReader).GetMethod("ReadInt64"))
					.newobj(typeof(DateTime), typeof(long))
					.stobj(typeof(DateTime));
			}
			#endregion

			#region string
			else if (elementType == typeof(string))
			{
				var strLen = deserializeEmit.DeclareLocal(typeof(int));
				var strNullLabel = deserializeEmit.DefineLabel();
				var strNotNullLabel = deserializeEmit.DefineLabel();
				deserializeEmit
					.ldarg_1
					.call(readIntMethod)
					.stloc(strLen)
					.ldloc(strLen)
					.ldc_i4_m1
					.ceq
					.brfalse(strNotNullLabel)
					.ldloc(arrayLocal)
					.ldloc(i)
					.ldelema(typeof(string))
					.ldnull
					.stobj(typeof(string))
					.br(strNullLabel)
					.MarkLabel(strNotNullLabel)
					.ldloc(arrayLocal)
					.ldloc(i)
					.ldelema(typeof(string))
					.ldarg_1
					.call(typeof(BinaryReader).GetMethod("ReadString"))
					.stobj(typeof(string))
					.MarkLabel(strNullLabel);
			}
			#endregion

			#region object
			var desElementNullLabel = deserializeEmit.DefineLabel();
			var desElementNotNullLabel = deserializeEmit.DefineLabel();
			var propertyInstanceType = deserializeEmit.DeclareLocal(typeof(Type));
			var indexLocal = deserializeEmit.DeclareLocal(typeof(int));
			var desobjectExistsLocal = deserializeEmit.DefineLabel();
			var desobjectNotExistsLocal = deserializeEmit.DefineLabel();
			deserializeEmit
				.ldarg_1
				.call(typeof(BinaryReader).GetMethod("ReadInt32"))
				.stloc(indexLocal)
				.ldloc(indexLocal)
				.ldc_i4_m1
				.ceq
				.brfalse(desElementNotNullLabel)
				.ldloc(arrayLocal)
				.ldloc(i)
				.ldelema(elementType)
				.ldnull
				.stobj(elementType)
				.br(desElementNullLabel)
				.MarkLabel(desElementNotNullLabel)
				.ldarg_2
				.ldloc(indexLocal)
				.call(typeof(IDictionary<int, object>).GetMethod("ContainsKey", new Type[] { typeof(int) }))
				.brfalse(desobjectNotExistsLocal)
				.ldloc(arrayLocal)
				.ldloc(i)
				.ldelema(elementType)
				.ldarg_2
				.ldloc(indexLocal)
				.call(typeof(IDictionary<int, object>).GetMethod("get_Item", new Type[] { typeof(int) }))
				.castclass(elementType)
				.stobj(elementType)
				.br(desobjectExistsLocal)
				.MarkLabel(desobjectNotExistsLocal)
				.ldarg_1
				.call(typeof(BinaryReader).GetMethod("ReadString"))
				.call(typeof(Type).GetMethod("GetType", new Type[] { typeof(string) }))
				.stloc(propertyInstanceType)
				.ldloc(arrayLocal)
				.ldloc(i)
				.ldelema(elementType)
				.ldloc(propertyInstanceType)
				.call(typeof(Activator).GetMethod("CreateInstance", new Type[] { typeof(Type) }))
				.castclass(elementType)
				.stobj(elementType)
				.ldarg_2
				.ldloc(indexLocal)
				.ldloc(arrayLocal)
				.ldloc(i)
				.ldelem_ref
				.call(typeof(IDictionary<int, object>).GetMethod("Add", new[] { typeof(int), typeof(object) }))
				.ldloc(arrayLocal)
				.ldloc(i)
				.ldelem_ref
				.castclass(typeof(ISerializable))
				.ldarg_1
				.ldarg_2
				.call(typeof(ISerializable).GetMethod("Deserialize", new Type[] { typeof(BinaryReader), typeof(IDictionary<int, object>) }))
				.MarkLabel(desobjectExistsLocal)
				.MarkLabel(desElementNullLabel);
			#endregion

			deserializeEmit
				.ldloc(i)
				.ldc_i4_1
				.add
				.stloc(i)
				.MarkLabel(beginForLabel)
				.ldloc(i)
				.ldloc(len)
				.clt
				.brtrue(beginForBodyLabel)
				.ldarg_0
				.ldloc(arrayLocal)
				.stfld(field)
				.MarkLabel(arrayNullLabel2);
		}