コード例 #1
0
        private void WriteFieldHandler(
            Compiler.CompilerContext ctx, Type expected, Compiler.Local loc,
            Compiler.CodeLabel handler, Compiler.CodeLabel @continue, IProtoSerializer serializer)
        {
            ctx.MarkLabel(handler);
            Type serType = serializer.ExpectedType;

            if (serType == ExpectedType)
            {
                EmitCreateIfNull(ctx, loc);
                serializer.EmitRead(ctx, loc);
            }
            else
            {
                //RuntimeTypeModel rtm = (RuntimeTypeModel)ctx.Model;
                if (((IProtoTypeSerializer)serializer).CanCreateInstance())
                {
                    Compiler.CodeLabel allDone = ctx.DefineLabel();

                    ctx.LoadValue(loc);
                    ctx.BranchIfFalse(allDone, false); // null is always ok

                    ctx.LoadValue(loc);
                    ctx.TryCast(serType);
                    ctx.BranchIfTrue(allDone, false); // not null, but of the correct type

                    // otherwise, need to convert it
                    ctx.LoadReader(false);
                    ctx.LoadValue(loc);
                    ((IProtoTypeSerializer)serializer).EmitCreateInstance(ctx);

                    ctx.EmitCall(typeof(ProtoReader).GetMethod("Merge",
                                                               new[] { typeof(ProtoReader), typeof(object), typeof(object) }));
                    ctx.Cast(expected);
                    ctx.StoreValue(loc); // Merge always returns a value

                    // nothing needs doing
                    ctx.MarkLabel(allDone);
                }

                if (Helpers.IsValueType(serType))
                {
                    Compiler.CodeLabel initValue = ctx.DefineLabel();
                    Compiler.CodeLabel hasValue  = ctx.DefineLabel();
                    using (Compiler.Local emptyValue = new Compiler.Local(ctx, serType))
                    {
                        ctx.LoadValue(loc);
                        ctx.BranchIfFalse(initValue, false);

                        ctx.LoadValue(loc);
                        ctx.CastFromObject(serType);
                        ctx.Branch(hasValue, false);

                        ctx.MarkLabel(initValue);
                        ctx.InitLocal(serType, emptyValue);
                        ctx.LoadValue(emptyValue);

                        ctx.MarkLabel(hasValue);
                    }
                }
                else
                {
                    ctx.LoadValue(loc);
                    ctx.Cast(serType);
                }

                serializer.EmitRead(ctx, null);
            }

            if (serializer.ReturnsValue)
            {   // update the variable
                if (Helpers.IsValueType(serType))
                {
                    // but box it first in case of value type
                    ctx.CastToObject(serType);
                }
                ctx.StoreValue(loc);
            }
            ctx.Branch(@continue, false); // "continue"
        }