示例#1
0
		public void Emit(FieldInfo field, ref EmitHelper serializerEmit, ref EmitHelper deserializeEmit)
		{
			var fieldType = field.FieldType;
			var writeIntMethod = typeof(BinaryWriter).GetMethod("Write", new[] { typeof(int) });
			var dictNotNullLabel = serializerEmit.DefineLabel();
			var dictNullLabel = serializerEmit.DefineLabel();
			var keyType = fieldType.GetGenericArguments()[0];
			if (!keyType.IsPrimitive && !(keyType == typeof(DateTime)) && !(keyType == typeof(string)) && !(keyType == typeof(decimal)))
			{
				throw new ArgumentException("Key type does not supported: " + keyType);
			}
			var valueType = fieldType.GetGenericArguments()[1];
			if (!valueType.IsPrimitive && !(valueType == typeof(DateTime)) && !(valueType == typeof(string)) && !(valueType == typeof(decimal)))
			{
				throw new ArgumentException("Value type does not supported: " + valueType);
			}
			var dictLocal = serializerEmit.DeclareLocal(fieldType);
			//construct ICollection<elementType> to call getCount method
			var keyValuePairType = typeof(KeyValuePair<,>);
			keyValuePairType = keyValuePairType.MakeGenericType(keyType, valueType);
			var getKeyMethod = keyValuePairType.GetMethod("get_Key");
			var getValueMethod = keyValuePairType.GetMethod("get_Value");
			var icollectionType = typeof(ICollection<>).MakeGenericType(keyValuePairType);
			var getCountMethod = icollectionType.GetMethod("get_Count");
			var enumeratorType = typeof(IEnumerator<>).MakeGenericType(keyValuePairType);
			var getEmumeratorMethod = typeof(IEnumerable<>).MakeGenericType(keyValuePairType).GetMethod("GetEnumerator");
			var getCurrentElementMethod = enumeratorType.GetMethod("get_Current");
			var keyValuePairLocal = serializerEmit.DeclareLocal(keyValuePairType);
			var enumeratorLocal = serializerEmit.DeclareLocal(enumeratorType);
			var startWhileLocal = serializerEmit.DefineLabel();
			var startWhileBodyLocal = serializerEmit.DefineLabel();
			var valueLocal = serializerEmit.DeclareLocal(valueType);
			var endFinallyLabel = serializerEmit.DefineLabel();
			serializerEmit
				.ldarg_0
				.ldfld(field)
				.stloc(dictLocal)
				.ldloc(dictLocal)
				.brtrue(dictNotNullLabel)
				.ldarg_1
				.ldc_i4_m1
				.call(writeIntMethod)
				.br(dictNullLabel)
				.MarkLabel(dictNotNullLabel);
			var exTryCatchFinallyLabel = serializerEmit.BeginExceptionBlock();
			serializerEmit
				.ldloc(dictLocal)
				.call(getEmumeratorMethod)
				.stloc(enumeratorLocal)
				.ldarg_1
				.ldloc(dictLocal)
				.call(getCountMethod)
				.call(writeIntMethod)
				.br(startWhileLocal)
				.MarkLabel(startWhileBodyLocal)
				.ldloc(enumeratorLocal)
				.call(getCurrentElementMethod)
				.stloc(keyValuePairLocal)
				.ldarg_1
				.ldloca(keyValuePairLocal)
				.call(getKeyMethod)
				.call(typeof(BinaryWriter).GetMethod("Write", new[] { keyType }));
			if (valueType == typeof(string))
			{
				var valueLocalNotNullLabel = serializerEmit.DefineLabel();
				var valueLocalNullLabel = serializerEmit.DefineLabel();
				serializerEmit
					.ldloca(keyValuePairLocal)
					.call(getValueMethod)
					.stloc(valueLocal)
					.ldloc(valueLocal)
					.brtrue(valueLocalNotNullLabel)
					.ldarg_1
					.ldc_i4_m1
					.call(typeof(BinaryWriter).GetMethod("Write", new[] { typeof(int) }))
					.br(valueLocalNullLabel)
					.MarkLabel(valueLocalNotNullLabel)
					.ldarg_1
					.ldloc(valueLocal)
					.call(typeof(string).GetMethod("get_Length"))
					.call(typeof(BinaryWriter).GetMethod("Write", new[] { typeof(int) }))
					.ldarg_1
					.ldloc(valueLocal)
					.call(typeof(BinaryWriter).GetMethod("Write", new[] { typeof(string) }))
					.MarkLabel(valueLocalNullLabel);
			}
			else if (valueType.IsPrimitive)
			{
				serializerEmit
					.ldarg_1
					.ldloca(keyValuePairLocal)
					.call(getValueMethod)
					.call(typeof(BinaryWriter).GetMethod("Write", new[] { valueType }));
			}
			serializerEmit
				.MarkLabel(startWhileLocal)
				.ldloc(enumeratorLocal)
				.call(typeof(IEnumerator).GetMethod("MoveNext"))
				.brtrue(startWhileBodyLocal)
				.leave(exTryCatchFinallyLabel)
				.BeginFinallyBlock()
				.ldloc(enumeratorLocal)
				.brfalse(endFinallyLabel)
				.ldloc(enumeratorLocal)
				.call(typeof(IDisposable).GetMethod("Dispose"))
				.MarkLabel(endFinallyLabel)
				.EndExceptionBlock()
				.MarkLabel(dictNullLabel);

			var readIntMethod = typeof(BinaryReader).GetMethod("ReadInt32");
			var addElementMethod = typeof(IDictionary<,>).MakeGenericType(keyType, valueType).GetMethod("Add", new[] { keyType, valueType });
			var dictNotNullLabel2 = deserializeEmit.DefineLabel();
			var dictNullLabel2 = deserializeEmit.DefineLabel();
			var deserializeDictLocal = deserializeEmit.DeclareLocal(fieldType);
			var len = deserializeEmit.DeclareLocal(typeof(int));
			var i = deserializeEmit.DeclareLocal(typeof(int));
			var beginForLabel = deserializeEmit.DefineLabel();
			var beginForBodyLabel = deserializeEmit.DefineLabel();

			var dictType = fieldType.IsInterface ? typeof(Dictionary<,>).MakeGenericType(keyType, valueType) : fieldType;
			var keyLocal = deserializeEmit.DeclareLocal(keyType);
			var valueLocal2 = deserializeEmit.DeclareLocal(valueType);

			deserializeEmit = deserializeEmit
				.ldarg_1
				.call(readIntMethod)
				.stloc(len)
				.ldloc(len)
				.ldc_i4_m1
				.ceq
				.brfalse(dictNotNullLabel2)
				.ldarg_0
				.ldnull
				.stfld(field)
				.br(dictNullLabel2)
				.MarkLabel(dictNotNullLabel2)
				.ldloc(len)
				.newobj(dictType, typeof(int))
				.stloc(deserializeDictLocal)
				.ldc_i4_0
				.stloc(i)
				.br(beginForLabel)
				.MarkLabel(beginForBodyLabel);
			if (keyType.IsPrimitive || keyType == typeof(decimal))
			{
				deserializeEmit
					.ldarg_1
					.call(typeof(BinaryReader).GetMethod("Read" + keyType.Name))
					.stloc(keyLocal);
			}
			else if (keyType == typeof(DateTime))
			{
				deserializeEmit
					.ldarg_1
					.call(typeof(BinaryReader).GetMethod("ReadInt64"))
					.newobj(typeof(DateTime), typeof(long))
					.stloc(keyLocal);
			}
			else if (keyType == typeof(string))
			{
				deserializeEmit
					.ldloca(keyLocal)
					.ldarg_1
					.call(typeof(BinaryReader).GetMethod("ReadString"))
					.stobj(typeof(string));
			}
			if (valueType.IsPrimitive || valueType == typeof(decimal))
			{
				deserializeEmit
					.ldarg_1
					.call(typeof(BinaryReader).GetMethod("Read" + keyType.Name))
					.stloc(valueLocal2);
			}
			else if (valueType == typeof(DateTime))
			{
				deserializeEmit
					.ldarg_1
					.call(typeof(BinaryReader).GetMethod("ReadInt64"))
					.newobj(typeof(DateTime), typeof(long))
					.stloc(valueLocal2);
			}
			else if (valueType == typeof(string))
			{
				var strNullLabel = deserializeEmit.DefineLabel();
				var strNotNullLabel = deserializeEmit.DefineLabel();
				deserializeEmit
					.ldarg_1
					.call(readIntMethod)
					.ldc_i4_m1
					.ceq
					.brfalse(strNotNullLabel)
					.ldnull
					.stloc(valueLocal2)
					.br(strNullLabel)
					.MarkLabel(strNotNullLabel)
					.ldarg_1
					.call(typeof(BinaryReader).GetMethod("ReadString"))
					.stloc(valueLocal2)
					.MarkLabel(strNullLabel);
			}
			deserializeEmit
				.ldloc(deserializeDictLocal)
				.ldloc(keyLocal)
				.ldloc(valueLocal2)
				.call(addElementMethod)
				.ldloc(i)
				.ldc_i4_1
				.add
				.stloc(i)
				.MarkLabel(beginForLabel)
				.ldloc(i)
				.ldloc(len)
				.clt
				.brtrue(beginForBodyLabel)
				.ldarg_0
				.ldloc(deserializeDictLocal)
				.stfld(field)
				.MarkLabel(dictNullLabel2);
		}