Beispiel #1
0
        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));
        }
Beispiel #3
0
        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);
        }
Beispiel #4
0
        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();
 }
Beispiel #6
0
        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);
        }
Beispiel #7
0
 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;
 }
Beispiel #9
0
        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));
        }
Beispiel #10
0
            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);
                    }
                }
            }
Beispiel #11
0
        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);
        }
Beispiel #12
0
        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));
        }
Beispiel #13
0
 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);
         }
     };
Beispiel #14
0
        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));
        }
Beispiel #15
0
        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);
        }
Beispiel #16
0
        /// <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);
        }
Beispiel #19
0
 public void Register <T>(CtxReadDelegate <T> reader, CtxWriteDelegate <T> writer, int?predefinedType = null)
 {
     myStore[typeof(T)] = new SerializerPair(reader, writer);
 }
Beispiel #20
0
            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();
            }
        }
Beispiel #25
0
            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);
 }
Beispiel #27
0
        /// <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>()
                {
                    { "", "" }
                }));
            });
        }