public override void ReadData(BinaryReader reader) { BinaryUtils.ReadList(reader, upgrades, (x) => (PlayerState.Upgrade)x.ReadInt32()); BinaryUtils.ReadList(reader, availUpgrades, (x) => (PlayerState.Upgrade)x.ReadInt32()); BinaryUtils.ReadDictionary(reader, upgradeLocks, (x) => (PlayerState.Upgrade)x.ReadInt32(), (x) => new PlayerState.UpgradeLockData(x.ReadBoolean(), x.ReadDouble())); BinaryUtils.ReadDictionary(reader, progress, (x) => (ProgressDirector.ProgressType)x.ReadInt32(), (x) => x.ReadInt32()); BinaryUtils.ReadDictionary(reader, delayedProgress, (x) => (ProgressDirector.ProgressTrackerId)x.ReadDouble(), (x) => x.ReadDouble()); BinaryUtils.ReadList(reader, blueprints, (x) => (Gadget.Id)x.ReadInt32()); BinaryUtils.ReadList(reader, availBlueprints, (x) => (Gadget.Id)x.ReadInt32()); BinaryUtils.ReadDictionary(reader, blueprintLocks, (x) => (Gadget.Id)x.ReadInt32(), (x) => new GadgetDirector.BlueprintLockData(x.ReadBoolean(), x.ReadDouble())); BinaryUtils.ReadDictionary(reader, gadgets, (x) => (Gadget.Id)x.ReadInt32(), (x) => x.ReadInt32()); BinaryUtils.ReadDictionary(reader, craftMatCounts, (x) => (Identifiable.Id)x.ReadInt32(), (x) => x.ReadInt32()); if (Version == 0) { return; } BinaryUtils.ReadList(reader, mail, (x) => { var v = new MailV02(); v.LoadData(reader); return(v); }); var enumser = SerializerPair.GetEnumSerializerPair <ZoneDirector.Zone>(); BinaryUtils.ReadList(reader, unlockedZoneMaps, (x) => (ZoneDirector.Zone)enumser.Deserialize(x)); }
public static SerializerPair CreateListSerializerPair <T>(SerializerPair itemSerializer) { CtxReadDelegate <IList <T> > readListSerializer = (ctx, reader) => reader.ReadList(itemSerializer.GetReader <T>(), ctx); CtxWriteDelegate <ICollection <T> > writeListSerializer = (ctx, writer, value) => writer.WriteCollection(itemSerializer.GetWriter <T>(), ctx, value); return(new SerializerPair(readListSerializer, writeListSerializer)); }
private SerializerPair TryGetIntrinsicSerializer(TypeInfo typeInfo) { if (!ReflectionSerializerVerifier.HasIntrinsicMethods(typeInfo)) { return(null); } var genericArguments = typeInfo.GetGenericArguments(); if (genericArguments.Length == 1) { var argument = genericArguments[0]; var staticRead = GetReadStaticSerializer(typeInfo, argument); var staticWrite = GetWriteStaticDeserializer(typeInfo); return(SerializerPair.CreateFromMethods(staticRead, staticWrite, GetOrRegisterSerializerInternal(argument))); } if (genericArguments.Length == 0) { var staticRead = GetReadStaticSerializer(typeInfo); var staticWrite = GetWriteStaticDeserializer(typeInfo); return(SerializerPair.CreateFromMethods(staticRead, staticWrite)); } return(null); }
private void RegisterScalar <T>() { myScalars.GetOrCreate <T>(out var reader, out var writer); var serializerPair = new SerializerPair(reader, writer); Assertion.Assert(!serializerPair.IsPolymorphic, "Polymorphic serializer can't be stored in staticSerializers"); mySerializers.Add(typeof(T), serializerPair); }
private static void WriteSerializePair(ILGenerator il, CompilerContext ctx, SerializerPair pair) { il.Emit(OpCodes.Ldarg_2); ctx.CastFromObject(pair.Type.Type); il.Emit(OpCodes.Ldarg_3); il.EmitCall(OpCodes.Call, pair.Serialize, null); ctx.Return(); }
public void RegisterPolymorphicSerializer([NotNull] Type type, SerializerPair serializers) { Assertion.Assert(CanBePolymorphic(type), $"Unable to register polymorphic serializer: {type.ToString(true)} is not a polymorphic type (it should be not sealed class or an interface)"); Assertion.Assert(!myStaticSerializers.ContainsKey(type), $"Unable to register polymorphic serializer: a static serializer for type {type.ToString(true)} already exists"); Assertion.Assert(!myPolySerializersSealed, $"Unable to register polymorphic serializer for type {type.ToString(true)}. It is too late to register a polymorphic serializer as one or more models were already activated."); myPolySerializers.Add(type, serializers); }
public PartialList(Predicate <T> hoistCondition, SerializerPair <T> serializer, Func <T> emptyValueCreator = null) { this.hoistCondition = hoistCondition; if (emptyValueCreator == null) { emptyValueCreator = () => default(T); } this.emptyValueCreator = emptyValueCreator; this.serializer = serializer; }
public PartialDictionary(Predicate <KeyValuePair <K, V> > hoistPredicate, SerializerPair <K> keySerializer, SerializerPair <V> valueSerializer, Func <KeyValuePair <K, V>, KeyValuePair <K, V>?> filler = null) { this.hoistPredicate = hoistPredicate; this.keySerializer = keySerializer; this.valueSerializer = valueSerializer; if (filler == null) { filler = (x) => null; } this.hoistFiller = filler; }
private SerializerPair CreateStaticReaderSingleGeneric(MemberInfo memberInfo, Type type, Type implementingType, bool allowNullable) { var argumentType = type.GetTypeInfo().GetGenericArguments()[0]; var readPropertyMethod = GetReadStaticSerializer(implementingType.GetTypeInfo(), argumentType); var writePropertyMethod = GetWriteStaticDeserializer(implementingType.GetTypeInfo()); var argumentSerializerPair = GetOrCreateMemberSerializer(memberInfo, serializerType: argumentType, allowNullable: allowNullable); return(SerializerPair.CreateFromMethods(readPropertyMethod, writePropertyMethod, argumentSerializerPair)); }
int IComparable.CompareTo(object obj) { if (obj == null) { throw new ArgumentException("obj"); } SerializerPair other = (SerializerPair)obj; // we want to bunch all the items with the same base-type together, but we need the items with a // different base **first**. if (this.BaseKey == this.MetaKey) { if (other.BaseKey == other.MetaKey) { // neither is a subclass return(this.MetaKey.CompareTo(other.MetaKey)); } else { // "other" (only) is involved in inheritance; "other" should be first return(1); } } else { if (other.BaseKey == other.MetaKey) { // "this" (only) is involved in inheritance; "this" should be first return(-1); } else { // both are involved in inheritance int result = this.BaseKey.CompareTo(other.BaseKey); if (result == 0) { result = this.MetaKey.CompareTo(other.MetaKey); } return(result); } } }
private SerializerPair CreateEnumSerializer <T>() { if (mySerializers.TryGetValue(typeof(T), out var serializerPair)) { return(serializerPair); } var readerParameter = Expression.Parameter(typeof(int), "reader"); var readerConvert = Expression.ConvertChecked(readerParameter, typeof(T)); var readerCaster = Expression.Lambda <Func <int, T> >(readerConvert, readerParameter).Compile(); var writerParameter = Expression.Parameter(typeof(T), "writer"); var writerConvert = Expression.ConvertChecked(writerParameter, typeof(int)); var writerCaster = Expression.Lambda <Func <T, int> >(writerConvert, writerParameter).Compile(); Assertion.Assert(typeof(T).IsSubclassOf(typeof(Enum)), "{0}", typeof(T)); var result = new SerializerPair( (CtxReadDelegate <T>)((ctx, reader) => readerCaster(reader.ReadInt())), (CtxWriteDelegate <T>)((ctx, w, o) => w.Write(writerCaster(o)))); mySerializers[typeof(T)] = result; return(result); }
public override void WriteData(BinaryWriter writer) { BinaryUtils.WriteList(writer, upgrades, (x, y) => x.Write((int)y)); BinaryUtils.WriteList(writer, availUpgrades, (x, y) => x.Write((int)y)); BinaryUtils.WriteDictionary(writer, upgradeLocks, (x, y) => x.Write((int)y), (x, y) => { x.Write(y.timedLock); x.Write(y.lockedUntil); }); BinaryUtils.WriteDictionary(writer, progress, (x, y) => x.Write((int)y), (x, y) => x.Write(y)); BinaryUtils.WriteDictionary(writer, delayedProgress, (x, y) => x.Write((int)y), (x, y) => x.Write(y)); BinaryUtils.WriteList(writer, blueprints, (x, y) => x.Write((int)y)); BinaryUtils.WriteList(writer, availBlueprints, (x, y) => x.Write((int)y)); BinaryUtils.WriteDictionary(writer, blueprintLocks, (x, y) => x.Write((int)y), (x, y) => { x.Write(y.timedLock); x.Write(y.lockedUntil); }); BinaryUtils.WriteDictionary(writer, gadgets, (x, y) => x.Write((int)y), (x, y) => x.Write(y)); BinaryUtils.WriteDictionary(writer, craftMatCounts, (x, y) => x.Write((int)y), (x, y) => x.Write(y)); BinaryUtils.WriteList(writer, mail, (x, y) => y.WriteData(x)); var enumser = SerializerPair.GetEnumSerializerPair <ZoneDirector.Zone>(); BinaryUtils.WriteList(writer, unlockedZoneMaps, (x, y) => enumser.Serialize(x, y)); }
public static SerializerPair CreateDictionarySerializerPair <TKey, TValue>(SerializerPair keySerializer, SerializerPair valueSerializer) { var read = CreateReadDictionary <TKey, TValue>(keySerializer, valueSerializer); CtxWriteDelegate <IDictionary <TKey, TValue> > write = (ctx, writer, value) => { if (value is Dictionary <TKey, TValue> val && !Equals(val.Comparer, EqualityComparer <TKey> .Default)) { throw new Exception($"Unable to serialize {value.GetType().ToString(true)}. Custom equality comparers are not supported"); } if (value == null) { writer.Write(-1); return; } writer.Write(value.Count); var keyw = keySerializer.GetWriter <TKey>(); var valuew = valueSerializer.GetWriter <TValue>(); foreach (var kvp in value) { keyw(ctx, writer, kvp.Key); valuew(ctx, writer, kvp.Value); } };
private SerializerPair CreateStaticReaderTwoGeneric([NotNull] MemberInfo memberInfo, [NotNull] Type type, [NotNull] Type implementingType) { var keyType = type.GetTypeInfo().GetGenericArguments()[0]; var valueType = type.GetTypeInfo().GetGenericArguments()[1]; var types = new[] { typeof(SerializationCtx), typeof(UnsafeReader), typeof(CtxReadDelegate <>).MakeGenericType(keyType), typeof(CtxWriteDelegate <>).MakeGenericType(keyType), typeof(CtxReadDelegate <>).MakeGenericType(valueType), typeof(CtxWriteDelegate <>).MakeGenericType(valueType) }; var methodInfo = implementingType.GetTypeInfo().GetMethod("Read", types); var readPropertyMethod = methodInfo.NotNull(); var writeStaticDeserializer = GetWriteStaticDeserializer(implementingType.GetTypeInfo()); var keySerializer = GetOrCreateMemberSerializer(memberInfo, serializerType: keyType, allowNullable: false); var valueSerializer = GetOrCreateMemberSerializer(memberInfo, serializerType: valueType, allowNullable: true); return(SerializerPair.CreateFromMethods(readPropertyMethod, writeStaticDeserializer, keySerializer, valueSerializer)); }
public static SerializerPair TryGetIntrinsicSerializer(TypeInfo typeInfo, Func <Type, SerializerPair> getInstanceSerializer) { if (ReflectionSerializerVerifier.HasIntrinsicNonProtocolMethods(typeInfo)) { var genericArguments = typeInfo.GetGenericArguments(); /* * if (genericArguments.Length == 1) * { * var argument = genericArguments[0]; * var staticRead = SerializerReflectionUtil.GetReadStaticSerializer(typeInfo, argument); * var staticWrite = SerializerReflectionUtil.GetWriteStaticDeserializer(typeInfo); * return SerializerPair.CreateFromMethods(staticRead, staticWrite, getInstanceSerializer(argument)); * } */ if (genericArguments.Length == 0) { var staticRead = SerializerReflectionUtil.GetReadStaticNonProtocolSerializer(typeInfo); var instanceWriter = SerializerReflectionUtil.GetWriteNonProtocolDeserializer(typeInfo); return(SerializerPair.CreateFromNonProtocolMethods(staticRead, instanceWriter)); } return(null); } if (ReflectionSerializerVerifier.HasIntrinsicProtocolMethods(typeInfo)) { var genericArguments = typeInfo.GetGenericArguments(); if (genericArguments.Length == 1) { var argument = genericArguments[0]; var staticRead = SerializerReflectionUtil.GetReadStaticSerializer(typeInfo, argument); var staticWrite = SerializerReflectionUtil.GetWriteStaticDeserializer(typeInfo); return(SerializerPair.CreateFromMethods(staticRead, staticWrite, getInstanceSerializer(argument))); } if (genericArguments.Length == 0) { var staticRead = SerializerReflectionUtil.GetReadStaticSerializer(typeInfo); var staticWrite = SerializerReflectionUtil.GetWriteStaticDeserializer(typeInfo); return(SerializerPair.CreateFromMethods(staticRead, staticWrite)); } return(null); } else if (ReflectionSerializerVerifier.HasIntrinsicFields(typeInfo)) { var readField = typeInfo.GetField("Read", BindingFlags.Public | BindingFlags.Static); var writeField = typeInfo.GetField("Write", BindingFlags.Public | BindingFlags.Static); if (readField == null) { Assertion.Fail($"Invalid intrinsic serializer for type {typeInfo}. Static field 'Read' with type {typeof(CtxReadDelegate<>).ToString(true)} not found"); } if (writeField == null) { Assertion.Fail($"Invalid intrinsic serializer for type {typeInfo}. Static field 'Write' with type {typeof(CtxWriteDelegate<>).ToString(true)} not found"); } var reader = readField.GetValue(null); var writer = writeField.GetValue(null); return(new SerializerPair(reader, writer)); } else if (ReflectionSerializerVerifier.HasIntrinsicAttribute(typeInfo)) { var marshallerType = typeInfo.GetCustomAttribute <RdScalarAttribute>().NotNull().Marshaller; var marshaller = Activator.CreateInstance(marshallerType); return((SerializerPair)ReflectionUtil.InvokeStaticGeneric(typeof(SerializerPair), nameof(SerializerPair.FromMarshaller), typeInfo, marshaller)); } return(null); }
/// <summary> /// Register serializers for either <see cref="RdExtAttribute"/> or <see cref="RdModelAttribute"/> /// </summary> private void RegisterModelSerializer <T>() { // place null marker to detect circular dependencies mySerializers.Add(typeof(T), null); TypeInfo typeInfo = typeof(T).GetTypeInfo(); ReflectionSerializerVerifier.AssertRoot(typeInfo); bool allowNullable = ReflectionSerializerVerifier.HasRdModelAttribute(typeInfo); var intrinsicSerializer = TryGetIntrinsicSerializer(typeInfo); if (intrinsicSerializer != null) { mySerializers[typeof(T)] = intrinsicSerializer; return; } var memberInfos = GetBindableMembers(typeInfo); var memberSetters = memberInfos.Select(ReflectionUtil.GetSetter).ToArray(); var memberGetters = memberInfos.Select(ReflectionUtil.GetGetter).ToArray(); // todo: consider using IL emit var memberDeserializers = new CtxReadDelegate <object> [memberInfos.Length]; var memberSerializers = new CtxWriteDelegate <object> [memberInfos.Length]; for (var index = 0; index < memberInfos.Length; index++) { var mi = memberInfos[index]; var returnType = ReflectionUtil.GetReturnType(mi); var serPair = GetOrCreateMemberSerializer(mi, serializerType: returnType, allowNullable: allowNullable); memberDeserializers[index] = ConvertReader(returnType, serPair.Reader); memberSerializers[index] = ConvertWriter(returnType, serPair.Writer); } var type = typeInfo.AsType(); CtxReadDelegate <T> readerDelegate = (ctx, unsafeReader) => { // todo: support non-default constructors var instance = Activator.CreateInstance(type); var bindableInstance = instance as IRdBindable; RdId id = default(RdId); if (bindableInstance != null) { id = unsafeReader.ReadRdId(); } for (var index = 0; index < memberDeserializers.Length; index++) { var value = memberDeserializers[index](ctx, unsafeReader); memberSetters[index](instance, value); } bindableInstance?.WithId(id); return((T)instance); }; CtxWriteDelegate <T> writerDelegate = (ctx, unsafeWriter, value) => { if (value is IRdBindable bindableInstance) { unsafeWriter.Write(bindableInstance.RdId); } for (var i = 0; i < memberDeserializers.Length; i++) { var memberValue = memberGetters[i](value); memberSerializers[i](ctx, unsafeWriter, memberValue); } }; mySerializers[type] = new SerializerPair(readerDelegate, writerDelegate); }
private static MethodBuilder EmitBoxedSerializer(TypeBuilder type, int i, Type valueType, SerializerPair[] methodPairs) { MethodInfo dedicated = methodPairs[i].Deserialize; MethodBuilder boxedSerializer = type.DefineMethod("_" + i, MethodAttributes.Static, CallingConventions.Standard, typeof(object), new Type[] { typeof(object), typeof(ProtoReader) }); Compiler.CompilerContext ctx = new Compiler.CompilerContext(boxedSerializer.GetILGenerator(), true, false, methodPairs); ctx.LoadValue(Compiler.Local.InputValue); Compiler.CodeLabel @null = ctx.DefineLabel(); ctx.BranchIfFalse(@null, true); ctx.LoadValue(Compiler.Local.InputValue); ctx.CastFromObject(valueType); ctx.LoadReaderWriter(); ctx.EmitCall(dedicated); ctx.CastToObject(valueType); ctx.Return(); ctx.MarkLabel(@null); using(Compiler.Local typedVal = new Compiler.Local(ctx, valueType)) { // create a new valueType ctx.LoadAddress(typedVal, valueType); ctx.EmitCtor(valueType); ctx.LoadValue(typedVal); ctx.LoadReaderWriter(); ctx.EmitCall(dedicated); ctx.CastToObject(valueType); ctx.Return(); } return boxedSerializer; }
private Compiler.CompilerContext WriteSerializeDeserialize(string assemblyName, TypeBuilder type, SerializerPair[] methodPairs, SerializerPair[] rootMethodPairs, Compiler.CompilerContext.ILVersion ilVersion, ref ILGenerator il) { Compiler.CompilerContext ctx; // arg0 = this, arg1 = key, arg2=obj, arg3=dest Compiler.CodeLabel[] jumpTable; { var genInfo = Override(type, "Serialize"); il = genInfo.GetILGenerator(); ctx = new Compiler.CompilerContext(genInfo, false, true, methodPairs, this, ilVersion, assemblyName, MapType(typeof(object))); jumpTable = new Compiler.CodeLabel[_types.Count]; for (int i = 0; i < jumpTable.Length; i++) { jumpTable[i] = ctx.DefineLabel(); } il.Emit(OpCodes.Ldarg_1); ctx.Switch(jumpTable); ctx.Return(); for (int i = 0; i < jumpTable.Length; i++) { SerializerPair pair = methodPairs[i]; ctx.MarkLabel(jumpTable[i]); var labelNoRoot = ctx.DefineLabel(); il.Emit(OpCodes.Ldarg_S, 4); ctx.BranchIfFalse(labelNoRoot, true); WriteSerializePair(il, ctx, rootMethodPairs[i]); ctx.MarkLabel(labelNoRoot); WriteSerializePair(il, ctx, pair); } } { var genInfo = Override(type, "Deserialize"); il = genInfo.GetILGenerator(); ctx = new Compiler.CompilerContext(genInfo, false, false, methodPairs, this, ilVersion, assemblyName, MapType(typeof(object))); // arg0 = this, arg1 = key, arg2=obj, arg3=source for (int i = 0; i < jumpTable.Length; i++) { jumpTable[i] = ctx.DefineLabel(); } il.Emit(OpCodes.Ldarg_1); ctx.Switch(jumpTable); ctx.LoadNullRef(); ctx.Return(); for (int i = 0; i < jumpTable.Length; i++) { SerializerPair pair = methodPairs[i]; ctx.MarkLabel(jumpTable[i]); var labelNoRoot = ctx.DefineLabel(); il.Emit(OpCodes.Ldarg_S, 4); ctx.BranchIfFalse(labelNoRoot, true); WriteDeserializePair(assemblyName, type, rootMethodPairs, ilVersion, il, rootMethodPairs[i], i, ctx); ctx.MarkLabel(labelNoRoot); WriteDeserializePair(assemblyName, type, methodPairs, ilVersion, il, pair, i, ctx); } } return(ctx); }
public void Register <T>(CtxReadDelegate <T> reader, CtxWriteDelegate <T> writer, int?predefinedType = null) { myStore[typeof(T)] = new SerializerPair(reader, writer); }
public static SerializerPair CreateFromMethods(MethodInfo readMethod, MethodInfo writeMethod, SerializerPair argumentSerializer) { void WriterDelegate(SerializationCtx ctx, UnsafeWriter writer, object value) => writeMethod.Invoke(null, new[] { ctx, writer, value, }); object ReaderDelegate(SerializationCtx ctx, UnsafeReader reader) => readMethod.Invoke(null, new[] { ctx, reader, argumentSerializer.Reader, argumentSerializer.Writer }); CtxReadDelegate <object> ctxReadDelegate = ReaderDelegate; CtxWriteDelegate <object> ctxWriteDelegate = WriterDelegate; return(new SerializerPair(ctxReadDelegate, ctxWriteDelegate)); }
public void TestCustomType() { WithBothFacades(f => f.ScalarSerializers.RegisterPolymorphicSerializer(typeof(IMyInterface), SerializerPair.FromMarshaller(new MyInterfaceMarshaller()))); WithExtsProxy <SimpleCalls, ISimpleCalls>((c, proxy) => { Assert.AreEqual(typeof(MyImpl2).Name, proxy.GetTypeName2(new MyImpl1())); }); }
private void WriteSerializers(CompilerOptions options, string assemblyName, TypeBuilder type, bool root, SerializerPair[] basicMethodPairs, out int index, out bool hasInheritance, out SerializerPair[] methodPairs, out Compiler.CompilerContext.ILVersion ilVersion) { Compiler.CompilerContext ctx; index = 0; hasInheritance = false; methodPairs = new SerializerPair[_types.Count]; foreach (MetaType metaType in _types) { string writeName = "Write"; if (root) { writeName += "Root"; } #if DEBUG writeName += metaType.Type.Name; #endif MethodContext writeGenCtx; MethodBuilder writeMethod = EmitDefineMethod( type, writeName, MethodAttributes.Private | MethodAttributes.Static, CallingConventions.Standard, MapType(typeof(void)), new[] { new MethodContext.ParameterGenInfo(metaType.Type, "obj", 1), new MethodContext.ParameterGenInfo(MapType(typeof(ProtoWriter)), "dest", 2), }, false, out writeGenCtx); string readName = "Read"; if (root) { readName += "Root"; } #if DEBUG readName += metaType.Type.Name; #endif MethodContext readGenCtx; MethodBuilder readMethod = EmitDefineMethod( type, readName, MethodAttributes.Private | MethodAttributes.Static, CallingConventions.Standard, metaType.Type, new[] { new MethodContext.ParameterGenInfo(metaType.Type, "obj", 1), new MethodContext.ParameterGenInfo(MapType(typeof(ProtoReader)), "source", 2), }, false, out readGenCtx); SerializerPair pair = new SerializerPair( GetKey(metaType.Type, true, false), GetKey(metaType.Type, true, true), metaType, writeMethod, readMethod, writeGenCtx, readGenCtx); methodPairs[index++] = pair; if (pair.MetaKey != pair.BaseKey) { hasInheritance = true; } } if (hasInheritance) { Array.Sort(methodPairs); } ilVersion = Compiler.CompilerContext.ILVersion.Net2; if (options.MetaDataVersion == 0x10000) { ilVersion = Compiler.CompilerContext.ILVersion.Net1; // old-school! } for (index = 0; index < methodPairs.Length; index++) { SerializerPair pair = methodPairs[index]; var ser = root ? pair.Type.RootSerializer : pair.Type.Serializer; ctx = new Compiler.CompilerContext(pair.SerializeBody, true, true, basicMethodPairs ?? methodPairs, this, ilVersion, assemblyName, pair.Type.Type); ctx.CheckAccessibility(pair.Deserialize.ReturnType); ser.EmitWrite(ctx, ctx.InputValue); ctx.Return(); ctx = new Compiler.CompilerContext(pair.DeserializeBody, true, false, basicMethodPairs ?? methodPairs, this, ilVersion, assemblyName, pair.Type.Type); ser.EmitRead(ctx, ctx.InputValue); if (!ser.EmitReadReturnsValue) { ctx.LoadValue(ctx.InputValue); } ctx.Return(); } }
private Compiler.CompilerContext WriteSerializeDeserialize(string assemblyName, TypeBuilder type, SerializerPair[] methodPairs, Compiler.CompilerContext.ILVersion ilVersion, ref ILGenerator il) { il = Override(type, "Serialize"); Compiler.CompilerContext ctx = new Compiler.CompilerContext(il, false, true, methodPairs, this, ilVersion, assemblyName, MapType(typeof(object))); // arg0 = this, arg1 = key, arg2=obj, arg3=dest Compiler.CodeLabel[] jumpTable = new Compiler.CodeLabel[types.Count]; for (int i = 0; i < jumpTable.Length; i++) { jumpTable[i] = ctx.DefineLabel(); } il.Emit(OpCodes.Ldarg_1); ctx.Switch(jumpTable); ctx.Return(); for (int i = 0; i < jumpTable.Length; i++) { SerializerPair pair = methodPairs[i]; ctx.MarkLabel(jumpTable[i]); il.Emit(OpCodes.Ldarg_2); ctx.CastFromObject(pair.Type.Type); il.Emit(OpCodes.Ldarg_3); il.EmitCall(OpCodes.Call, pair.Serialize, null); ctx.Return(); } il = Override(type, "Deserialize"); ctx = new Compiler.CompilerContext(il, false, false, methodPairs, this, ilVersion, assemblyName, MapType(typeof(object))); // arg0 = this, arg1 = key, arg2=obj, arg3=source for (int i = 0; i < jumpTable.Length; i++) { jumpTable[i] = ctx.DefineLabel(); } il.Emit(OpCodes.Ldarg_1); ctx.Switch(jumpTable); ctx.LoadNullRef(); ctx.Return(); for (int i = 0; i < jumpTable.Length; i++) { SerializerPair pair = methodPairs[i]; ctx.MarkLabel(jumpTable[i]); Type keyType = pair.Type.Type; if (keyType.IsValueType) { il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldarg_3); il.EmitCall(OpCodes.Call, EmitBoxedSerializer(type, i, keyType, methodPairs, this, ilVersion, assemblyName), null); ctx.Return(); } else { il.Emit(OpCodes.Ldarg_2); ctx.CastFromObject(keyType); il.Emit(OpCodes.Ldarg_3); il.EmitCall(OpCodes.Call, pair.Deserialize, null); ctx.Return(); } } return ctx; }
private void WriteSerializers(CompilerOptions options, string assemblyName, TypeBuilder type, out int index, out bool hasInheritance, out SerializerPair[] methodPairs, out Compiler.CompilerContext.ILVersion ilVersion) { Compiler.CompilerContext ctx; index = 0; hasInheritance = false; methodPairs = new SerializerPair[types.Count]; foreach (MetaType metaType in types) { MethodBuilder writeMethod = type.DefineMethod("Write" #if DEBUG + metaType.Type.Name #endif , MethodAttributes.Private | MethodAttributes.Static, CallingConventions.Standard, MapType(typeof(void)), new Type[] { metaType.Type, MapType(typeof(ProtoWriter)) }); MethodBuilder readMethod = type.DefineMethod("Read" #if DEBUG + metaType.Type.Name #endif , MethodAttributes.Private | MethodAttributes.Static, CallingConventions.Standard, metaType.Type, new Type[] { metaType.Type, MapType(typeof(ProtoReader)) }); SerializerPair pair = new SerializerPair( GetKey(metaType.Type, true, false), GetKey(metaType.Type, true, true), metaType, writeMethod, readMethod, writeMethod.GetILGenerator(), readMethod.GetILGenerator()); methodPairs[index++] = pair; if (pair.MetaKey != pair.BaseKey) hasInheritance = true; } if (hasInheritance) { Array.Sort(methodPairs); } ilVersion = Compiler.CompilerContext.ILVersion.Net2; if (options.MetaDataVersion == 0x10000) { ilVersion = Compiler.CompilerContext.ILVersion.Net1; // old-school! } for (index = 0; index < methodPairs.Length; index++) { SerializerPair pair = methodPairs[index]; ctx = new Compiler.CompilerContext(pair.SerializeBody, true, true, methodPairs, this, ilVersion, assemblyName, pair.Type.Type); ctx.CheckAccessibility(pair.Deserialize.ReturnType); pair.Type.Serializer.EmitWrite(ctx, ctx.InputValue); ctx.Return(); ctx = new Compiler.CompilerContext(pair.DeserializeBody, true, false, methodPairs, this, ilVersion, assemblyName, pair.Type.Type); pair.Type.Serializer.EmitRead(ctx, ctx.InputValue); if (!pair.Type.Serializer.ReturnsValue) { ctx.LoadValue(ctx.InputValue); } ctx.Return(); } }
public static SerializerPair CreateFromMethods(MethodInfo readMethod, MethodInfo writeMethod, SerializerPair keySerializer, SerializerPair valueSerializer) { var ctxKeyReadDelegate = keySerializer.Reader; var ctxKeyWriteDelegate = keySerializer.Writer; var ctxValueReadDelegate = valueSerializer.Reader; var ctxValueWriteDelegate = valueSerializer.Writer; void WriterDelegate(SerializationCtx ctx, UnsafeWriter writer, object value) { writeMethod.Invoke(null, new[] { ctx, writer, value, }); } object ReaderDelegate(SerializationCtx ctx, UnsafeReader reader) { return(readMethod.Invoke(null, new[] { ctx, reader, ctxKeyReadDelegate, ctxKeyWriteDelegate, ctxValueReadDelegate, ctxValueWriteDelegate })); } var ctxReadDelegate = (CtxReadDelegate <object>)ReaderDelegate; var ctxWriteDelegate = (CtxWriteDelegate <object>)WriterDelegate; return(new SerializerPair(ctxReadDelegate, ctxWriteDelegate)); }
public PartialCollection(Predicate <T> hoistCondition, SerializerPair <T> serializer, Predicate <T> valueFilter = null) { this.hoistCondition = hoistCondition; this.serializer = serializer; this.forbiddenValueTester = valueFilter ?? (x => true); }
/// <summary> /// Fully compiles the current model into a static-compiled serialization dll /// (the serialization dll still requires protobuf-net for support services). /// </summary> /// <remarks>A full compilation is restricted to accessing public types / members</remarks> /// <param name="name">The name of the TypeModel class to create</param> /// <param name="path">The path for the new dll</param> /// <returns>An instance of the newly created compiled type-model</returns> public TypeModel Compile(string name, string path) { BuildAllSerializers(); Freeze(); bool save = !Helpers.IsNullOrEmpty(path); if (Helpers.IsNullOrEmpty(name)) { if (save) { throw new ArgumentNullException("name"); } name = Guid.NewGuid().ToString(); } AssemblyName an = new AssemblyName(); an.Name = name; AssemblyBuilder asm = AppDomain.CurrentDomain.DefineDynamicAssembly(an, (save ? AssemblyBuilderAccess.RunAndSave : AssemblyBuilderAccess.Run) ); ModuleBuilder module = save ? asm.DefineDynamicModule(name, path) : asm.DefineDynamicModule(name); Type baseType = typeof(TypeModel); TypeBuilder type = module.DefineType(name, (baseType.Attributes & ~TypeAttributes.Abstract) | TypeAttributes.Sealed, baseType); Compiler.CompilerContext ctx; int index = 0; bool hasInheritance = false; SerializerPair[] methodPairs = new SerializerPair[types.Count]; foreach (MetaType metaType in types) { MethodBuilder writeMethod = type.DefineMethod("Write", MethodAttributes.Private | MethodAttributes.Static, CallingConventions.Standard, typeof(void), new Type[] { metaType.Type, typeof(ProtoWriter) }); MethodBuilder readMethod = type.DefineMethod("Read", MethodAttributes.Private | MethodAttributes.Static, CallingConventions.Standard, metaType.Type, new Type[] { metaType.Type, typeof(ProtoReader) }); SerializerPair pair = new SerializerPair( GetKey(metaType.Type, true, false), GetKey(metaType.Type, true, true), metaType, writeMethod, readMethod, writeMethod.GetILGenerator(), readMethod.GetILGenerator()); methodPairs[index++] = pair; if (pair.MetaKey != pair.BaseKey) { hasInheritance = true; } } if (hasInheritance) { Array.Sort(methodPairs); } for (index = 0; index < methodPairs.Length; index++) { SerializerPair pair = methodPairs[index]; ctx = new Compiler.CompilerContext(pair.SerializeBody, true, methodPairs); pair.Type.Serializer.EmitWrite(ctx, Compiler.Local.InputValue); ctx.Return(); ctx = new Compiler.CompilerContext(pair.DeserializeBody, true, methodPairs); pair.Type.Serializer.EmitRead(ctx, Compiler.Local.InputValue); ctx.LoadValue(Compiler.Local.InputValue); ctx.Return(); } FieldBuilder knownTypes = type.DefineField("knownTypes", typeof(Type[]), FieldAttributes.Private | FieldAttributes.InitOnly); ILGenerator il = Override(type, "GetKeyImpl"); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, knownTypes); il.Emit(OpCodes.Ldarg_1); // note that Array.IndexOf is not supported under CF il.EmitCall(OpCodes.Callvirt, typeof(IList).GetMethod( "IndexOf", new Type[] { typeof(object) }), null); if (hasInheritance) { il.DeclareLocal(typeof(int)); // loc-0 il.Emit(OpCodes.Dup); il.Emit(OpCodes.Stloc_0); BasicList getKeyLabels = new BasicList(); int lastKey = -1; for (int i = 0; i < methodPairs.Length; i++) { if (methodPairs[i].MetaKey == methodPairs[i].BaseKey) { break; } if (lastKey == methodPairs[i].BaseKey) { // add the last label again getKeyLabels.Add(getKeyLabels[getKeyLabels.Count - 1]); } else { // add a new unique label getKeyLabels.Add(il.DefineLabel()); lastKey = methodPairs[i].BaseKey; } } Label[] subtypeLabels = new Label[getKeyLabels.Count]; getKeyLabels.CopyTo(subtypeLabels, 0); il.Emit(OpCodes.Switch, subtypeLabels); il.Emit(OpCodes.Ldloc_0); // not a sub-type; use the original value il.Emit(OpCodes.Ret); lastKey = -1; // now output the different branches per sub-type (not derived type) for (int i = subtypeLabels.Length - 1; i >= 0; i--) { if (lastKey != methodPairs[i].BaseKey) { lastKey = methodPairs[i].BaseKey; // find the actual base-index for this base-key (i.e. the index of // the base-type) int keyIndex = -1; for (int j = subtypeLabels.Length; j < methodPairs.Length; j++) { if (methodPairs[j].BaseKey == lastKey && methodPairs[j].MetaKey == lastKey) { keyIndex = j; break; } } il.MarkLabel(subtypeLabels[i]); Compiler.CompilerContext.LoadValue(il, keyIndex); il.Emit(OpCodes.Ret); } } } else { il.Emit(OpCodes.Ret); } il = Override(type, "Serialize"); ctx = new Compiler.CompilerContext(il, false, methodPairs); // arg0 = this, arg1 = key, arg2=obj, arg3=dest Label[] jumpTable = new Label[types.Count]; for (int i = 0; i < jumpTable.Length; i++) { jumpTable[i] = il.DefineLabel(); } il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Switch, jumpTable); ctx.Return(); for (int i = 0; i < jumpTable.Length; i++) { SerializerPair pair = methodPairs[i]; il.MarkLabel(jumpTable[i]); il.Emit(OpCodes.Ldarg_2); ctx.CastFromObject(pair.Type.Type); il.Emit(OpCodes.Ldarg_3); il.EmitCall(OpCodes.Call, pair.Serialize, null); ctx.Return(); } il = Override(type, "Deserialize"); ctx = new Compiler.CompilerContext(il, false, methodPairs); // arg0 = this, arg1 = key, arg2=obj, arg3=source for (int i = 0; i < jumpTable.Length; i++) { jumpTable[i] = il.DefineLabel(); } il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Switch, jumpTable); ctx.LoadNullRef(); ctx.Return(); for (int i = 0; i < jumpTable.Length; i++) { SerializerPair pair = methodPairs[i]; il.MarkLabel(jumpTable[i]); Type keyType = pair.Type.Type; if (keyType.IsValueType) { il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldarg_3); il.EmitCall(OpCodes.Call, EmitBoxedSerializer(type, i, keyType, methodPairs), null); ctx.Return(); } else { il.Emit(OpCodes.Ldarg_2); ctx.CastFromObject(keyType); il.Emit(OpCodes.Ldarg_3); il.EmitCall(OpCodes.Call, pair.Deserialize, null); ctx.Return(); } } ConstructorBuilder ctor = type.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, Helpers.EmptyTypes); il = ctor.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Call, baseType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance)[0]); il.Emit(OpCodes.Ldarg_0); Compiler.CompilerContext.LoadValue(il, types.Count); il.Emit(OpCodes.Newarr, typeof(Type)); index = 0; foreach (SerializerPair pair in methodPairs) { il.Emit(OpCodes.Dup); Compiler.CompilerContext.LoadValue(il, index); il.Emit(OpCodes.Ldtoken, pair.Type.Type); il.EmitCall(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"), null); il.Emit(OpCodes.Stelem_Ref); index++; } il.Emit(OpCodes.Stfld, knownTypes); il.Emit(OpCodes.Ret); Type finalType = type.CreateType(); if (!Helpers.IsNullOrEmpty(path)) { asm.Save(path); Helpers.DebugWriteLine("Wrote dll:" + path); } return((TypeModel)Activator.CreateInstance(finalType)); }
private void WriteDeserializePair(string assemblyName, TypeBuilder type, SerializerPair[] methodPairs, CompilerContext.ILVersion ilVersion, ILGenerator il, SerializerPair pair, int i, CompilerContext ctx) { Type keyType = pair.Type.Type; if (keyType.IsValueType) { il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldarg_3); il.EmitCall(OpCodes.Call, EmitBoxedSerializer(type, i, keyType, methodPairs, this, ilVersion, assemblyName).Member, null); ctx.Return(); } else { il.Emit(OpCodes.Ldarg_2); ctx.CastFromObject(keyType); il.Emit(OpCodes.Ldarg_3); il.EmitCall(OpCodes.Call, pair.Deserialize, null); ctx.Return(); } }
private void WriteConstructors(TypeBuilder type, ref int index, SerializerPair[] methodPairs, ref ILGenerator il, int knownTypesCategory, FieldBuilder knownTypes, Type knownTypesLookupType, Compiler.CompilerContext ctx) { type.DefineDefaultConstructor(MethodAttributes.Public); il = type.DefineTypeInitializer().GetILGenerator(); switch (knownTypesCategory) { case KnownTypes_Array: { Compiler.CompilerContext.LoadValue(il, types.Count); il.Emit(OpCodes.Newarr, ctx.MapType(typeof(System.Type))); index = 0; foreach (SerializerPair pair in methodPairs) { il.Emit(OpCodes.Dup); Compiler.CompilerContext.LoadValue(il, index); il.Emit(OpCodes.Ldtoken, pair.Type.Type); il.EmitCall(OpCodes.Call, ctx.MapType(typeof(System.Type)).GetMethod("GetTypeFromHandle"), null); il.Emit(OpCodes.Stelem_Ref); index++; } il.Emit(OpCodes.Stsfld, knownTypes); il.Emit(OpCodes.Ret); } break; case KnownTypes_Dictionary: { Compiler.CompilerContext.LoadValue(il, types.Count); //LocalBuilder loc = il.DeclareLocal(knownTypesLookupType); il.Emit(OpCodes.Newobj, knownTypesLookupType.GetConstructor(new Type[] { MapType(typeof(int)) })); il.Emit(OpCodes.Stsfld, knownTypes); int typeIndex = 0; foreach (SerializerPair pair in methodPairs) { il.Emit(OpCodes.Ldsfld, knownTypes); il.Emit(OpCodes.Ldtoken, pair.Type.Type); il.EmitCall(OpCodes.Call, ctx.MapType(typeof(System.Type)).GetMethod("GetTypeFromHandle"), null); int keyIndex = typeIndex++, lastKey = pair.BaseKey; if (lastKey != pair.MetaKey) // not a base-type; need to give the index of the base-type { keyIndex = -1; // assume epic fail for (int j = 0; j < methodPairs.Length; j++) { if (methodPairs[j].BaseKey == lastKey && methodPairs[j].MetaKey == lastKey) { keyIndex = j; break; } } } Compiler.CompilerContext.LoadValue(il, keyIndex); il.EmitCall(OpCodes.Callvirt, knownTypesLookupType.GetMethod("Add", new Type[] { MapType(typeof(System.Type)), MapType(typeof(int)) }), null); } il.Emit(OpCodes.Ret); } break; case KnownTypes_Hashtable: { Compiler.CompilerContext.LoadValue(il, types.Count); il.Emit(OpCodes.Newobj, knownTypesLookupType.GetConstructor(new Type[] { MapType(typeof(int)) })); il.Emit(OpCodes.Stsfld, knownTypes); int typeIndex = 0; foreach (SerializerPair pair in methodPairs) { il.Emit(OpCodes.Ldsfld, knownTypes); il.Emit(OpCodes.Ldtoken, pair.Type.Type); il.EmitCall(OpCodes.Call, ctx.MapType(typeof(System.Type)).GetMethod("GetTypeFromHandle"), null); int keyIndex = typeIndex++, lastKey = pair.BaseKey; if (lastKey != pair.MetaKey) // not a base-type; need to give the index of the base-type { keyIndex = -1; // assume epic fail for (int j = 0; j < methodPairs.Length; j++) { if (methodPairs[j].BaseKey == lastKey && methodPairs[j].MetaKey == lastKey) { keyIndex = j; break; } } } Compiler.CompilerContext.LoadValue(il, keyIndex); il.Emit(OpCodes.Box, MapType(typeof(int))); il.EmitCall(OpCodes.Callvirt, knownTypesLookupType.GetMethod("Add", new Type[] { MapType(typeof(object)), MapType(typeof(object)) }), null); } il.Emit(OpCodes.Ret); } break; default: throw new InvalidOperationException(); } }
/// <summary> /// Fully compiles the current model into a static-compiled serialization dll /// (the serialization dll still requires protobuf-net for support services). /// </summary> /// <remarks>A full compilation is restricted to accessing public types / members</remarks> /// <returns>An instance of the newly created compiled type-model</returns> public TypeModel Compile(CompilerOptions options) { if (options == null) throw new ArgumentNullException("options"); string typeName = options.TypeName; string path = options.OutputPath; BuildAllSerializers(); Freeze(); bool save = !Helpers.IsNullOrEmpty(path); if (Helpers.IsNullOrEmpty(typeName)) { if (save) throw new ArgumentNullException("typeName"); typeName = Guid.NewGuid().ToString(); } string assemblyName, moduleName; if(path == null) { assemblyName = typeName; moduleName = assemblyName + ".dll"; } else { assemblyName = new System.IO.FileInfo(System.IO.Path.GetFileNameWithoutExtension(path)).Name; moduleName = assemblyName + System.IO.Path.GetExtension(path); } #if FEAT_IKVM IKVM.Reflection.AssemblyName an = new IKVM.Reflection.AssemblyName(); an.Name = assemblyName; AssemblyBuilder asm = universe.DefineDynamicAssembly(an, AssemblyBuilderAccess.Save); if(!Helpers.IsNullOrEmpty(options.ImageRuntimeVersion) && options.MetaDataVersion != 0) { asm.__SetImageRuntimeVersion(options.ImageRuntimeVersion, options.MetaDataVersion); } ModuleBuilder module = asm.DefineDynamicModule(moduleName, path); #else AssemblyName an = new AssemblyName(); an.Name = assemblyName; AssemblyBuilder asm = AppDomain.CurrentDomain.DefineDynamicAssembly(an, (save ? AssemblyBuilderAccess.RunAndSave : AssemblyBuilderAccess.Run) ); ModuleBuilder module = save ? asm.DefineDynamicModule(moduleName, path) : asm.DefineDynamicModule(moduleName); #endif if (!Helpers.IsNullOrEmpty(options.TargetFrameworkName)) { // get [TargetFramework] from mscorlib/equivalent and burn into the new assembly Type versionAttribType = null; try { // this is best-endeavours only versionAttribType = GetType("System.Runtime.Versioning.TargetFrameworkAttribute", MapType(typeof(string)).Assembly); } catch { /* don't stress */ } if (versionAttribType != null) { PropertyInfo[] props; object[] propValues; if (Helpers.IsNullOrEmpty(options.TargetFrameworkDisplayName)) { props = new PropertyInfo[0]; propValues = new object[0]; } else { props = new PropertyInfo[1] { versionAttribType.GetProperty("FrameworkDisplayName") }; propValues = new object[1] { options.TargetFrameworkDisplayName }; } CustomAttributeBuilder builder = new CustomAttributeBuilder( versionAttribType.GetConstructor(new Type[] { MapType(typeof(string)) }), new object[] { options.TargetFrameworkName }, props, propValues); asm.SetCustomAttribute(builder); } } // copy assembly:InternalsVisibleTo Type internalsVisibleToAttribType = null; #if !FX11 try { internalsVisibleToAttribType = MapType(typeof(System.Runtime.CompilerServices.InternalsVisibleToAttribute)); } catch { /* best endeavors only */ } #endif if (internalsVisibleToAttribType != null) { BasicList internalAssemblies = new BasicList(), consideredAssemblies = new BasicList(); foreach (MetaType metaType in types) { Assembly assembly = metaType.Type.Assembly; if (consideredAssemblies.IndexOfReference(assembly) >= 0) continue; consideredAssemblies.Add(assembly); AttributeMap[] assemblyAttribsMap = AttributeMap.Create(this, assembly); for (int i = 0; i < assemblyAttribsMap.Length; i++) { if (assemblyAttribsMap[i].AttributeType != internalsVisibleToAttribType) continue; object privelegedAssemblyObj; assemblyAttribsMap[i].TryGet("AssemblyName", out privelegedAssemblyObj); string privelegedAssemblyName = privelegedAssemblyObj as string; if (privelegedAssemblyName == assemblyName || Helpers.IsNullOrEmpty(privelegedAssemblyName)) continue; // ignore if (internalAssemblies.IndexOf(new StringFinder(privelegedAssemblyName)) >= 0) continue; // seen it before internalAssemblies.Add(privelegedAssemblyName); CustomAttributeBuilder builder = new CustomAttributeBuilder( internalsVisibleToAttribType.GetConstructor(new Type[] { MapType(typeof(string)) }), new object[] { privelegedAssemblyName }); asm.SetCustomAttribute(builder); } } } Type baseType = MapType(typeof(TypeModel)); TypeAttributes typeAttributes = (baseType.Attributes & ~TypeAttributes.Abstract) | TypeAttributes.Sealed; if(options.Accessibility == Accessibility.Internal) { typeAttributes &= ~TypeAttributes.Public; } TypeBuilder type = module.DefineType(typeName, typeAttributes, baseType); Compiler.CompilerContext ctx; int index = 0; bool hasInheritance = false; SerializerPair[] methodPairs = new SerializerPair[types.Count]; foreach (MetaType metaType in types) { MethodBuilder writeMethod = type.DefineMethod("Write" #if DEBUG + metaType.Type.Name #endif , MethodAttributes.Private | MethodAttributes.Static, CallingConventions.Standard, MapType(typeof(void)), new Type[] { metaType.Type, MapType(typeof(ProtoWriter)) }); MethodBuilder readMethod = type.DefineMethod("Read" #if DEBUG + metaType.Type.Name #endif , MethodAttributes.Private | MethodAttributes.Static, CallingConventions.Standard, metaType.Type, new Type[] { metaType.Type, MapType(typeof(ProtoReader)) }); SerializerPair pair = new SerializerPair( GetKey(metaType.Type, true, false), GetKey(metaType.Type, true, true), metaType, writeMethod, readMethod, writeMethod.GetILGenerator(), readMethod.GetILGenerator()); methodPairs[index++] = pair; if (pair.MetaKey != pair.BaseKey) hasInheritance = true; } if (hasInheritance) { Array.Sort(methodPairs); } Compiler.CompilerContext.ILVersion ilVersion = Compiler.CompilerContext.ILVersion.Net2; if (options.MetaDataVersion == 0x10000) { ilVersion = Compiler.CompilerContext.ILVersion.Net1; // old-school! } for(index = 0; index < methodPairs.Length ; index++) { SerializerPair pair = methodPairs[index]; ctx = new Compiler.CompilerContext(pair.SerializeBody, true, true, methodPairs, this, ilVersion, assemblyName); ctx.CheckAccessibility(pair.Deserialize.ReturnType); pair.Type.Serializer.EmitWrite(ctx, Compiler.Local.InputValue); ctx.Return(); ctx = new Compiler.CompilerContext(pair.DeserializeBody, true, false, methodPairs, this, ilVersion, assemblyName); pair.Type.Serializer.EmitRead(ctx, Compiler.Local.InputValue); if (!pair.Type.Serializer.ReturnsValue) { ctx.LoadValue(Compiler.Local.InputValue); } ctx.Return(); } ILGenerator il = Override(type, "GetKeyImpl"); int knownTypesCategory; FieldBuilder knownTypes; Type knownTypesLookupType; const int KnownTypes_Array = 1, KnownTypes_Dictionary = 2, KnownTypes_Hashtable = 3, KnownTypes_ArrayCutoff = 20; if (types.Count <= KnownTypes_ArrayCutoff) { knownTypesCategory = KnownTypes_Array; knownTypesLookupType = MapType(typeof(System.Type[]), true); } else { #if NO_GENERICS knownTypesLookupType = null; #else knownTypesLookupType = MapType(typeof(System.Collections.Generic.Dictionary<System.Type, int>), false); #endif if (knownTypesLookupType == null) { knownTypesLookupType = MapType(typeof(Hashtable), true); knownTypesCategory = KnownTypes_Hashtable; } else { knownTypesCategory = KnownTypes_Dictionary; } } knownTypes = type.DefineField("knownTypes", knownTypesLookupType, FieldAttributes.Private | FieldAttributes.InitOnly | FieldAttributes.Static); switch(knownTypesCategory) { case KnownTypes_Array: { il.Emit(OpCodes.Ldsfld, knownTypes); il.Emit(OpCodes.Ldarg_1); // note that Array.IndexOf is not supported under CF il.EmitCall(OpCodes.Callvirt, MapType(typeof(IList)).GetMethod( "IndexOf", new Type[] { MapType(typeof(object)) }), null); if (hasInheritance) { il.DeclareLocal(MapType(typeof(int))); // loc-0 il.Emit(OpCodes.Dup); il.Emit(OpCodes.Stloc_0); BasicList getKeyLabels = new BasicList(); int lastKey = -1; for (int i = 0; i < methodPairs.Length; i++) { if (methodPairs[i].MetaKey == methodPairs[i].BaseKey) break; if (lastKey == methodPairs[i].BaseKey) { // add the last label again getKeyLabels.Add(getKeyLabels[getKeyLabels.Count - 1]); } else { // add a new unique label getKeyLabels.Add(il.DefineLabel()); lastKey = methodPairs[i].BaseKey; } } Label[] subtypeLabels = new Label[getKeyLabels.Count]; getKeyLabels.CopyTo(subtypeLabels, 0); il.Emit(OpCodes.Switch, subtypeLabels); il.Emit(OpCodes.Ldloc_0); // not a sub-type; use the original value il.Emit(OpCodes.Ret); lastKey = -1; // now output the different branches per sub-type (not derived type) for (int i = subtypeLabels.Length - 1; i >= 0; i--) { if (lastKey != methodPairs[i].BaseKey) { lastKey = methodPairs[i].BaseKey; // find the actual base-index for this base-key (i.e. the index of // the base-type) int keyIndex = -1; for (int j = subtypeLabels.Length; j < methodPairs.Length; j++) { if (methodPairs[j].BaseKey == lastKey && methodPairs[j].MetaKey == lastKey) { keyIndex = j; break; } } il.MarkLabel(subtypeLabels[i]); Compiler.CompilerContext.LoadValue(il, keyIndex); il.Emit(OpCodes.Ret); } } } else { il.Emit(OpCodes.Ret); } } break; case KnownTypes_Dictionary: { LocalBuilder result = il.DeclareLocal(MapType(typeof(int))); Label otherwise = il.DefineLabel(); il.Emit(OpCodes.Ldsfld, knownTypes); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldloca_S, result); il.EmitCall(OpCodes.Callvirt, knownTypesLookupType.GetMethod("TryGetValue", BindingFlags.Instance | BindingFlags.Public), null); il.Emit(OpCodes.Brfalse_S, otherwise); il.Emit(OpCodes.Ldloc_S, result); il.Emit(OpCodes.Ret); il.MarkLabel(otherwise); il.Emit(OpCodes.Ldc_I4_M1); il.Emit(OpCodes.Ret); } break; case KnownTypes_Hashtable: { Label otherwise = il.DefineLabel(); il.Emit(OpCodes.Ldsfld, knownTypes); il.Emit(OpCodes.Ldarg_1); il.EmitCall(OpCodes.Callvirt, knownTypesLookupType.GetProperty("Item").GetGetMethod(), null); il.Emit(OpCodes.Dup); il.Emit(OpCodes.Brfalse_S, otherwise); #if FX11 il.Emit(OpCodes.Unbox, MapType(typeof(int))); il.Emit(OpCodes.Ldobj, MapType(typeof(int))); #else if (ilVersion == Compiler.CompilerContext.ILVersion.Net1) { il.Emit(OpCodes.Unbox, MapType(typeof(int))); il.Emit(OpCodes.Ldobj, MapType(typeof(int))); } else { il.Emit(OpCodes.Unbox_Any, MapType(typeof(int))); } #endif il.Emit(OpCodes.Ret); il.MarkLabel(otherwise); il.Emit(OpCodes.Pop); il.Emit(OpCodes.Ldc_I4_M1); il.Emit(OpCodes.Ret); } break; default: throw new InvalidOperationException(); } il = Override(type, "Serialize"); ctx = new Compiler.CompilerContext(il, false, true, methodPairs, this, ilVersion, assemblyName); // arg0 = this, arg1 = key, arg2=obj, arg3=dest Label[] jumpTable = new Label[types.Count]; for (int i = 0; i < jumpTable.Length; i++) { jumpTable[i] = il.DefineLabel(); } il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Switch, jumpTable); ctx.Return(); for (int i = 0; i < jumpTable.Length; i++) { SerializerPair pair = methodPairs[i]; il.MarkLabel(jumpTable[i]); il.Emit(OpCodes.Ldarg_2); ctx.CastFromObject(pair.Type.Type); il.Emit(OpCodes.Ldarg_3); il.EmitCall(OpCodes.Call, pair.Serialize, null); ctx.Return(); } il = Override(type, "Deserialize"); ctx = new Compiler.CompilerContext(il, false, false, methodPairs, this, ilVersion, assemblyName); // arg0 = this, arg1 = key, arg2=obj, arg3=source for (int i = 0; i < jumpTable.Length; i++) { jumpTable[i] = il.DefineLabel(); } il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Switch, jumpTable); ctx.LoadNullRef(); ctx.Return(); for (int i = 0; i < jumpTable.Length; i++) { SerializerPair pair = methodPairs[i]; il.MarkLabel(jumpTable[i]); Type keyType = pair.Type.Type; if (keyType.IsValueType) { il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldarg_3); il.EmitCall(OpCodes.Call, EmitBoxedSerializer(type, i, keyType, methodPairs, this, ilVersion, assemblyName), null); ctx.Return(); } else { il.Emit(OpCodes.Ldarg_2); ctx.CastFromObject(keyType); il.Emit(OpCodes.Ldarg_3); il.EmitCall(OpCodes.Call, pair.Deserialize, null); ctx.Return(); } } type.DefineDefaultConstructor(MethodAttributes.Public); il = type.DefineTypeInitializer().GetILGenerator(); switch (knownTypesCategory) { case KnownTypes_Array: { Compiler.CompilerContext.LoadValue(il, types.Count); il.Emit(OpCodes.Newarr, ctx.MapType(typeof(System.Type))); index = 0; foreach (SerializerPair pair in methodPairs) { il.Emit(OpCodes.Dup); Compiler.CompilerContext.LoadValue(il, index); il.Emit(OpCodes.Ldtoken, pair.Type.Type); il.EmitCall(OpCodes.Call, ctx.MapType(typeof(System.Type)).GetMethod("GetTypeFromHandle"), null); il.Emit(OpCodes.Stelem_Ref); index++; } il.Emit(OpCodes.Stsfld, knownTypes); il.Emit(OpCodes.Ret); } break; case KnownTypes_Dictionary: { Compiler.CompilerContext.LoadValue(il, types.Count); LocalBuilder loc = il.DeclareLocal(knownTypesLookupType); il.Emit(OpCodes.Newobj, knownTypesLookupType.GetConstructor(new Type[] { MapType(typeof(int)) })); il.Emit(OpCodes.Stsfld, knownTypes); int typeIndex = 0; foreach (SerializerPair pair in methodPairs) { il.Emit(OpCodes.Ldsfld, knownTypes); il.Emit(OpCodes.Ldtoken, pair.Type.Type); il.EmitCall(OpCodes.Call, ctx.MapType(typeof(System.Type)).GetMethod("GetTypeFromHandle"), null); int keyIndex = typeIndex++, lastKey = pair.BaseKey; if (lastKey != pair.MetaKey) // not a base-type; need to give the index of the base-type { keyIndex = -1; // assume epic fail for (int j = 0; j < methodPairs.Length; j++) { if (methodPairs[j].BaseKey == lastKey && methodPairs[j].MetaKey == lastKey) { keyIndex = j; break; } } } Compiler.CompilerContext.LoadValue(il, keyIndex); il.EmitCall(OpCodes.Callvirt, knownTypesLookupType.GetMethod("Add", new Type[] { MapType(typeof(System.Type)), MapType(typeof(int)) }), null); } il.Emit(OpCodes.Ret); } break; case KnownTypes_Hashtable: { Compiler.CompilerContext.LoadValue(il, types.Count); il.Emit(OpCodes.Newobj, knownTypesLookupType.GetConstructor(new Type[] { MapType(typeof(int)) })); il.Emit(OpCodes.Stsfld, knownTypes); int typeIndex = 0; foreach (SerializerPair pair in methodPairs) { il.Emit(OpCodes.Ldsfld, knownTypes); il.Emit(OpCodes.Ldtoken, pair.Type.Type); il.EmitCall(OpCodes.Call, ctx.MapType(typeof(System.Type)).GetMethod("GetTypeFromHandle"), null); int keyIndex = typeIndex++, lastKey = pair.BaseKey; if (lastKey != pair.MetaKey) // not a base-type; need to give the index of the base-type { keyIndex = -1; // assume epic fail for (int j = 0; j < methodPairs.Length; j++) { if (methodPairs[j].BaseKey == lastKey && methodPairs[j].MetaKey == lastKey) { keyIndex = j; break; } } } Compiler.CompilerContext.LoadValue(il, keyIndex); il.Emit(OpCodes.Box, MapType(typeof(int))); il.EmitCall(OpCodes.Callvirt, knownTypesLookupType.GetMethod("Add", new Type[] { MapType(typeof(object)), MapType(typeof(object)) }), null); } il.Emit(OpCodes.Ret); } break; default: throw new InvalidOperationException(); } Type finalType = type.CreateType(); if(!Helpers.IsNullOrEmpty(path)) { asm.Save(path); Helpers.DebugWriteLine("Wrote dll:" + path); } #if FEAT_IKVM return null; #else return (TypeModel)Activator.CreateInstance(finalType); #endif }
private void WriteGetKeyImpl(TypeBuilder type, bool hasInheritance, SerializerPair[] methodPairs, Compiler.CompilerContext.ILVersion ilVersion, string assemblyName, out ILGenerator il, out int knownTypesCategory, out FieldBuilder knownTypes, out Type knownTypesLookupType) { il = Override(type, "GetKeyImpl"); Compiler.CompilerContext ctx = new Compiler.CompilerContext(il, false, false, methodPairs, this, ilVersion, assemblyName, MapType(typeof(System.Type), true)); if (types.Count <= KnownTypes_ArrayCutoff) { knownTypesCategory = KnownTypes_Array; knownTypesLookupType = MapType(typeof(System.Type[]), true); } else { #if NO_GENERICS knownTypesLookupType = null; #else knownTypesLookupType = MapType(typeof(System.Collections.Generic.Dictionary<System.Type, int>), false); #endif if (knownTypesLookupType == null) { knownTypesLookupType = MapType(typeof(Hashtable), true); knownTypesCategory = KnownTypes_Hashtable; } else { knownTypesCategory = KnownTypes_Dictionary; } } knownTypes = type.DefineField("knownTypes", knownTypesLookupType, FieldAttributes.Private | FieldAttributes.InitOnly | FieldAttributes.Static); switch (knownTypesCategory) { case KnownTypes_Array: { il.Emit(OpCodes.Ldsfld, knownTypes); il.Emit(OpCodes.Ldarg_1); // note that Array.IndexOf is not supported under CF il.EmitCall(OpCodes.Callvirt, MapType(typeof(IList)).GetMethod( "IndexOf", new Type[] { MapType(typeof(object)) }), null); if (hasInheritance) { il.DeclareLocal(MapType(typeof(int))); // loc-0 il.Emit(OpCodes.Dup); il.Emit(OpCodes.Stloc_0); BasicList getKeyLabels = new BasicList(); int lastKey = -1; for (int i = 0; i < methodPairs.Length; i++) { if (methodPairs[i].MetaKey == methodPairs[i].BaseKey) break; if (lastKey == methodPairs[i].BaseKey) { // add the last label again getKeyLabels.Add(getKeyLabels[getKeyLabels.Count - 1]); } else { // add a new unique label getKeyLabels.Add(ctx.DefineLabel()); lastKey = methodPairs[i].BaseKey; } } Compiler.CodeLabel[] subtypeLabels = new Compiler.CodeLabel[getKeyLabels.Count]; getKeyLabels.CopyTo(subtypeLabels, 0); ctx.Switch(subtypeLabels); il.Emit(OpCodes.Ldloc_0); // not a sub-type; use the original value il.Emit(OpCodes.Ret); lastKey = -1; // now output the different branches per sub-type (not derived type) for (int i = subtypeLabels.Length - 1; i >= 0; i--) { if (lastKey != methodPairs[i].BaseKey) { lastKey = methodPairs[i].BaseKey; // find the actual base-index for this base-key (i.e. the index of // the base-type) int keyIndex = -1; for (int j = subtypeLabels.Length; j < methodPairs.Length; j++) { if (methodPairs[j].BaseKey == lastKey && methodPairs[j].MetaKey == lastKey) { keyIndex = j; break; } } ctx.MarkLabel(subtypeLabels[i]); Compiler.CompilerContext.LoadValue(il, keyIndex); il.Emit(OpCodes.Ret); } } } else { il.Emit(OpCodes.Ret); } } break; case KnownTypes_Dictionary: { LocalBuilder result = il.DeclareLocal(MapType(typeof(int))); Label otherwise = il.DefineLabel(); il.Emit(OpCodes.Ldsfld, knownTypes); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldloca_S, result); il.EmitCall(OpCodes.Callvirt, knownTypesLookupType.GetMethod("TryGetValue", BindingFlags.Instance | BindingFlags.Public), null); il.Emit(OpCodes.Brfalse_S, otherwise); il.Emit(OpCodes.Ldloc_S, result); il.Emit(OpCodes.Ret); il.MarkLabel(otherwise); il.Emit(OpCodes.Ldc_I4_M1); il.Emit(OpCodes.Ret); } break; case KnownTypes_Hashtable: { Label otherwise = il.DefineLabel(); il.Emit(OpCodes.Ldsfld, knownTypes); il.Emit(OpCodes.Ldarg_1); il.EmitCall(OpCodes.Callvirt, knownTypesLookupType.GetProperty("Item").GetGetMethod(), null); il.Emit(OpCodes.Dup); il.Emit(OpCodes.Brfalse_S, otherwise); #if FX11 il.Emit(OpCodes.Unbox, MapType(typeof(int))); il.Emit(OpCodes.Ldobj, MapType(typeof(int))); #else if (ilVersion == Compiler.CompilerContext.ILVersion.Net1) { il.Emit(OpCodes.Unbox, MapType(typeof(int))); il.Emit(OpCodes.Ldobj, MapType(typeof(int))); } else { il.Emit(OpCodes.Unbox_Any, MapType(typeof(int))); } #endif il.Emit(OpCodes.Ret); il.MarkLabel(otherwise); il.Emit(OpCodes.Pop); il.Emit(OpCodes.Ldc_I4_M1); il.Emit(OpCodes.Ret); } break; default: throw new InvalidOperationException(); } }
/// <summary> /// Fully compiles the current model into a static-compiled serialization dll /// (the serialization dll still requires protobuf-net for support services). /// </summary> /// <remarks>A full compilation is restricted to accessing public types / members</remarks> /// <param name="name">The name of the TypeModel class to create</param> /// <param name="path">The path for the new dll</param> /// <returns>An instance of the newly created compiled type-model</returns> public TypeModel Compile(string name, string path) { BuildAllSerializers(); Freeze(); bool save = !Helpers.IsNullOrEmpty(path); if (Helpers.IsNullOrEmpty(name)) { if (save) throw new ArgumentNullException("name"); name = Guid.NewGuid().ToString(); } AssemblyName an = new AssemblyName(); an.Name = name; AssemblyBuilder asm = AppDomain.CurrentDomain.DefineDynamicAssembly(an, (save ? AssemblyBuilderAccess.RunAndSave : AssemblyBuilderAccess.Run) ); ModuleBuilder module = save ? asm.DefineDynamicModule(name, path) : asm.DefineDynamicModule(name); Type baseType = typeof(TypeModel); TypeBuilder type = module.DefineType(name, (baseType.Attributes & ~TypeAttributes.Abstract) | TypeAttributes.Sealed, baseType); Compiler.CompilerContext ctx; int index = 0; bool hasInheritance = false; SerializerPair[] methodPairs = new SerializerPair[types.Count]; foreach (MetaType metaType in types) { MethodBuilder writeMethod = type.DefineMethod("Write" #if DEBUG + metaType.Type.Name #endif , MethodAttributes.Private | MethodAttributes.Static, CallingConventions.Standard, typeof(void), new Type[] { metaType.Type, typeof(ProtoWriter) }); MethodBuilder readMethod = type.DefineMethod("Read" #if DEBUG + metaType.Type.Name #endif , MethodAttributes.Private | MethodAttributes.Static, CallingConventions.Standard, metaType.Type, new Type[] { metaType.Type, typeof(ProtoReader) }); SerializerPair pair = new SerializerPair( GetKey(metaType.Type, true, false), GetKey(metaType.Type, true, true), metaType, writeMethod, readMethod, writeMethod.GetILGenerator(), readMethod.GetILGenerator()); methodPairs[index++] = pair; if (pair.MetaKey != pair.BaseKey) hasInheritance = true; } if (hasInheritance) { Array.Sort(methodPairs); } for(index = 0; index < methodPairs.Length ; index++) { SerializerPair pair = methodPairs[index]; ctx = new Compiler.CompilerContext(pair.SerializeBody, true, true, methodPairs); pair.Type.Serializer.EmitWrite(ctx, Compiler.Local.InputValue); ctx.Return(); ctx = new Compiler.CompilerContext(pair.DeserializeBody, true, false, methodPairs); pair.Type.Serializer.EmitRead(ctx, Compiler.Local.InputValue); if (!pair.Type.Serializer.ReturnsValue) { ctx.LoadValue(Compiler.Local.InputValue); } ctx.Return(); } FieldBuilder knownTypes = type.DefineField("knownTypes", typeof(Type[]), FieldAttributes.Private | FieldAttributes.InitOnly); ILGenerator il = Override(type, "GetKeyImpl"); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, knownTypes); il.Emit(OpCodes.Ldarg_1); // note that Array.IndexOf is not supported under CF il.EmitCall(OpCodes.Callvirt,typeof(IList).GetMethod( "IndexOf", new Type[] { typeof(object) }), null); if (hasInheritance) { il.DeclareLocal(typeof(int)); // loc-0 il.Emit(OpCodes.Dup); il.Emit(OpCodes.Stloc_0); BasicList getKeyLabels = new BasicList(); int lastKey = -1; for (int i = 0; i < methodPairs.Length; i++) { if (methodPairs[i].MetaKey == methodPairs[i].BaseKey) break; if (lastKey == methodPairs[i].BaseKey) { // add the last label again getKeyLabels.Add(getKeyLabels[getKeyLabels.Count - 1]); } else { // add a new unique label getKeyLabels.Add(il.DefineLabel()); lastKey = methodPairs[i].BaseKey; } } Label[] subtypeLabels = new Label[getKeyLabels.Count]; getKeyLabels.CopyTo(subtypeLabels, 0); il.Emit(OpCodes.Switch, subtypeLabels); il.Emit(OpCodes.Ldloc_0); // not a sub-type; use the original value il.Emit(OpCodes.Ret); lastKey = -1; // now output the different branches per sub-type (not derived type) for (int i = subtypeLabels.Length - 1; i >= 0; i--) { if (lastKey != methodPairs[i].BaseKey) { lastKey = methodPairs[i].BaseKey; // find the actual base-index for this base-key (i.e. the index of // the base-type) int keyIndex = -1; for (int j = subtypeLabels.Length; j < methodPairs.Length; j++) { if (methodPairs[j].BaseKey == lastKey && methodPairs[j].MetaKey == lastKey) { keyIndex = j; break; } } il.MarkLabel(subtypeLabels[i]); Compiler.CompilerContext.LoadValue(il, keyIndex); il.Emit(OpCodes.Ret); } } } else { il.Emit(OpCodes.Ret); } il = Override(type, "Serialize"); ctx = new Compiler.CompilerContext(il, false, true, methodPairs); // arg0 = this, arg1 = key, arg2=obj, arg3=dest Label[] jumpTable = new Label[types.Count]; for (int i = 0; i < jumpTable.Length; i++) { jumpTable[i] = il.DefineLabel(); } il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Switch, jumpTable); ctx.Return(); for (int i = 0; i < jumpTable.Length; i++) { SerializerPair pair = methodPairs[i]; il.MarkLabel(jumpTable[i]); il.Emit(OpCodes.Ldarg_2); ctx.CastFromObject(pair.Type.Type); il.Emit(OpCodes.Ldarg_3); il.EmitCall(OpCodes.Call, pair.Serialize, null); ctx.Return(); } il = Override(type, "Deserialize"); ctx = new Compiler.CompilerContext(il, false, false, methodPairs); // arg0 = this, arg1 = key, arg2=obj, arg3=source for (int i = 0; i < jumpTable.Length; i++) { jumpTable[i] = il.DefineLabel(); } il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Switch, jumpTable); ctx.LoadNullRef(); ctx.Return(); for (int i = 0; i < jumpTable.Length; i++) { SerializerPair pair = methodPairs[i]; il.MarkLabel(jumpTable[i]); Type keyType = pair.Type.Type; if (keyType.IsValueType) { il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldarg_3); il.EmitCall(OpCodes.Call, EmitBoxedSerializer(type, i, keyType, methodPairs), null); ctx.Return(); } else { il.Emit(OpCodes.Ldarg_2); ctx.CastFromObject(keyType); il.Emit(OpCodes.Ldarg_3); il.EmitCall(OpCodes.Call, pair.Deserialize, null); ctx.Return(); } } ConstructorBuilder ctor = type.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, Helpers.EmptyTypes); il = ctor.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Call, Helpers.GetConstructor(baseType, Helpers.EmptyTypes, true)); il.Emit(OpCodes.Ldarg_0); Compiler.CompilerContext.LoadValue(il, types.Count); il.Emit(OpCodes.Newarr, typeof(Type)); index = 0; foreach(SerializerPair pair in methodPairs) { il.Emit(OpCodes.Dup); Compiler.CompilerContext.LoadValue(il, index); il.Emit(OpCodes.Ldtoken, pair.Type.Type); il.EmitCall(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"), null); il.Emit(OpCodes.Stelem_Ref); index++; } il.Emit(OpCodes.Stfld, knownTypes); il.Emit(OpCodes.Ret); Type finalType = type.CreateType(); if(!Helpers.IsNullOrEmpty(path)) { asm.Save(path); Helpers.DebugWriteLine("Wrote dll:" + path); } return (TypeModel)Activator.CreateInstance(finalType); }
private static MethodBuilder EmitBoxedSerializer(TypeBuilder type, int i, Type valueType, SerializerPair[] methodPairs, TypeModel model, Compiler.CompilerContext.ILVersion ilVersion, string assemblyName) { MethodInfo dedicated = methodPairs[i].Deserialize; MethodBuilder boxedSerializer = type.DefineMethod("_" + i.ToString(), MethodAttributes.Static, CallingConventions.Standard, model.MapType(typeof(object)), new Type[] { model.MapType(typeof(object)), model.MapType(typeof(ProtoReader)) }); Compiler.CompilerContext ctx = new Compiler.CompilerContext(boxedSerializer.GetILGenerator(), true, false, methodPairs, model, ilVersion, assemblyName, model.MapType(typeof(object))); ctx.LoadValue(ctx.InputValue); Compiler.CodeLabel @null = ctx.DefineLabel(); ctx.BranchIfFalse(@null, true); Type mappedValueType = valueType; ctx.LoadValue(ctx.InputValue); ctx.CastFromObject(mappedValueType); ctx.LoadReaderWriter(); ctx.EmitCall(dedicated); ctx.CastToObject(mappedValueType); ctx.Return(); ctx.MarkLabel(@null); using (Compiler.Local typedVal = new Compiler.Local(ctx, mappedValueType)) { // create a new valueType ctx.LoadAddress(typedVal, mappedValueType); ctx.EmitCtor(mappedValueType); ctx.LoadValue(typedVal); ctx.LoadReaderWriter(); ctx.EmitCall(dedicated); ctx.CastToObject(mappedValueType); ctx.Return(); } return boxedSerializer; }
public void TestCustomType() { WithBothFacades(f => f.ScalarSerializers.RegisterPolymorphicSerializer(typeof(IMyInterface), SerializerPair.FromMarshaller(new MyInterfaceMarshaller()))); WithExtsProxy <SimpleCalls, ISimpleCalls>((c, proxy) => { var instanceSerializer = CFacade.ScalarSerializers.GetInstanceSerializer(typeof(IReadOnlyDictionary <string, string>)); Assert.AreEqual(typeof(MyImpl2).Name, proxy.GetTypeName2(new MyImpl1())); proxy.GetTypeName3(new IMyInterface[] { new MyImpl1(), new MyImpl2() }); Assert.AreEqual(1, proxy.ReadonlyDictionaryCount(new Dictionary <string, string>() { { "", "" } })); }); }