private IEnumerable <Expression> CreateTupleItemExpressions(ParameterExpression objectTreeParameter, IList <Type> flattenTypes)
        {
            var tupleTypeList = TupleItems.CreateTupleTypeList(flattenTypes);

            int depth = -1;

            for (int i = 0; i < flattenTypes.Count; i++)
            {
                if (i % 7 == 0)
                {
                    depth++;
                }

                Expression current = objectTreeParameter;
                for (int j = 0; j < depth; j++)
                {
                    // .TRest.TRest ...
                    var rest = tupleTypeList[j].GetProperty("Rest");
                    current = Expression.Property(current, rest);
                }

                var itemn = tupleTypeList[depth].GetProperty("Item" + ((i % 7) + 1));
#if DEBUG
                Contract.Assert(itemn != null, tupleTypeList[depth].GetFullName() + "::Item" + ((i % 7) + 1) + " [ " + depth + " ] @ " + i);
#endif
                yield return(Expression.Property(current, itemn));
            }
        }
        public ReflectionTupleMessagePackSerializer(SerializationContext ownerContext)
            : base(ownerContext)
        {
            var itemTypes = TupleItems.GetTupleItemTypes(typeof(T));

            this._itemSerializers   = itemTypes.Select(itemType => ownerContext.GetSerializer(itemType)).ToArray();
            this._tupleTypes        = TupleItems.CreateTupleTypeList(itemTypes);
            this._tupleConstructors = this._tupleTypes.Select(tupleType => tupleType.GetConstructors().Single()).ToArray();
            this._getters           = GetGetters(itemTypes, this._tupleTypes).ToArray();
        }
Beispiel #3
0
        public ReflectionTupleMessagePackSerializer(SerializationContext ownerContext, IList <PolymorphismSchema> itemSchemas)
            : base(ownerContext)
        {
            var itemTypes = TupleItems.GetTupleItemTypes(typeof(T));

            this._itemSerializers =
                itemTypes.Select(
                    (itemType, i) => ownerContext.GetSerializer(itemType, itemSchemas.Count == 0 ? null : itemSchemas[i])
                    ).ToArray();
            this._tupleTypes        = TupleItems.CreateTupleTypeList(itemTypes);
            this._tupleConstructors = this._tupleTypes.Select(tupleType => tupleType.GetConstructors().Single()).ToArray();
            this._getters           = GetGetters(itemTypes, this._tupleTypes).ToArray();
        }
Beispiel #4
0
        private IEnumerable <TConstruct> BuildTuplePackToCore(TContext context, IList <Type> itemTypes, IList <PolymorphismSchema> itemSchemaList)
        {
            // Put cardinality as array length.
            yield return(this.EmitPutArrayHeaderExpression(context, this.MakeInt32Literal(context, itemTypes.Count)));

            var depth                   = -1;
            var tupleTypeList           = TupleItems.CreateTupleTypeList(itemTypes);
            var propertyInvocationChain = new List <PropertyInfo>(itemTypes.Count % 7 + 1);

            for (int i = 0; i < itemTypes.Count; i++)
            {
                if (i % 7 == 0)
                {
                    depth++;
                }

                for (int j = 0; j < depth; j++)
                {
                    // .TRest.TRest ...
                    var restProperty = tupleTypeList[j].GetProperty("Rest");
#if DEBUG
                    Contract.Assert(restProperty != null);
#endif
                    propertyInvocationChain.Add(restProperty);
                }

                var itemNProperty = tupleTypeList[depth].GetProperty("Item" + ((i % 7) + 1));
                propertyInvocationChain.Add(itemNProperty);
#if DEBUG
                Contract.Assert(
                    itemNProperty != null,
                    tupleTypeList[depth].GetFullName() + "::Item" + ((i % 7) + 1) + " [ " + depth + " ] @ " + i);
#endif
                foreach (var packTupleItem in
                         this.EmitPackTupleItemStatements(
                             context,
                             itemTypes[i],
                             context.Packer,
                             context.PackToTarget,
                             propertyInvocationChain,
                             itemSchemaList.Count == 0 ? null : itemSchemaList[i]
                             )
                         )
                {
                    yield return(packTupleItem);
                }

                propertyInvocationChain.Clear();
            }
        }
        public ReflectionTupleMessagePackSerializer(SerializationContext ownerContext, IList <PolymorphismSchema> itemSchemas)
            : base(ownerContext, SerializerCapabilities.PackTo | SerializerCapabilities.UnpackFrom)
        {
            var itemTypes = TupleItems.GetTupleItemTypes(typeof(T));

            this._itemSerializers =
                itemTypes.Select(
                    (itemType, i) => ownerContext.GetSerializer(itemType, itemSchemas.Count == 0 ? null : itemSchemas[i])
                    ).ToArray();
            this._tupleTypes        = TupleItems.CreateTupleTypeList(typeof(T));
            this._tupleConstructors = this._tupleTypes.Select(tupleType => tupleType.GetConstructors().SingleOrDefault()).ToArray();
            this._getters           =
                typeof(T).GetIsValueType()
                                        ? GetGetters(
                    itemTypes,
                    this._tupleTypes,
                    (type, name) => type.GetField(name),
                    f => f,
                    getters =>
                    tuple =>
            {
                object current = tuple;
                foreach (var getter in getters)
                {
                    current = getter.GetValue(current);
                }

                return(current);
            }
                    ).ToArray()
                                        : GetGetters(
                    itemTypes,
                    this._tupleTypes,
                    (type, name) => type.GetProperty(name),
                    p => p.GetGetMethod(),
                    getters =>
                    tuple =>
            {
                object current = tuple;
                foreach (var getter in getters)
                {
                    current = getter.InvokePreservingExceptionType(current);
                }

                return(current);
            }
                    ).ToArray();
        }
        private Expression CreateNestedTupleCreationExpression(IList <Type> itemTypes, IEnumerable <Expression> itemExpressions)
        {
            var tupleTypeList = TupleItems.CreateTupleTypeList(itemTypes);

            Expression right = null;

            for (int depth = tupleTypeList.Count - 1; 0 <= depth; depth--)
            {
                var constructor = tupleTypeList[depth].GetConstructors().Single();
                var args        = itemExpressions.Skip(depth * 7).Take(Math.Min(constructor.GetParameters().Length, 7));
                if (right != null)
                {
                    args = args.Concat(new[] { right });
                }

                right = Expression.New(constructor, args);
            }

            return(right);
        }
        private IEnumerable <TConstruct> BuildTupleUnpackFromCore(TContext context, IList <Type> itemTypes)
        {
            var tupleTypeList = TupleItems.CreateTupleTypeList(itemTypes);

            yield return
                (this.EmitCheckIsArrayHeaderExpression(context, context.Unpacker));

            yield return
                (this.EmitCheckTupleCardinarityExpression(
                     context,
                     context.Unpacker,
                     itemTypes.Count
                     ));

            var unpackedItems =
                itemTypes.Select(
                    (type, i) =>
                    this.DeclareLocal(
                        context,
                        type,
                        "item" + i
                        )
                    ).ToArray();

            var unpackItems =
                itemTypes.Select(
                    (unpackedNullableItemType, i) =>
                    this.EmitUnpackItemValueExpression(
                        context,
                        unpackedNullableItemType,
                        context.TupleItemNilImplication,
                        context.Unpacker,
                        this.MakeInt32Literal(context, i),
                        this.MakeStringLiteral(context, "Item" + i.ToString(CultureInfo.InvariantCulture)),
                        null,
                        null,
                        null,
                        unpackedItem =>
                        this.EmitStoreVariableStatement(
                            context,
                            unpackedItems[i],
                            unpackedItem
                            )
                        )
                    );

            TConstruct currentTuple = null;

            for (int nest = tupleTypeList.Count - 1; nest >= 0; nest--)
            {
                var items = unpackedItems.Skip(nest * 7).Take(Math.Min(unpackedItems.Length, 7));
                currentTuple =
                    this.EmitCreateNewObjectExpression(
                        context,
                        null,                         // Tuple is reference contextType.
                        tupleTypeList[nest].GetConstructors().Single(),
                        currentTuple == null
                                                        ? items.ToArray()
                                                        : items.ToArray().Concat(new[] { currentTuple }).ToArray()
                        );
            }

#if DEBUG
            Contract.Assert(currentTuple != null);
#endif
            yield return
                (this.EmitSequentialStatements(
                     context,
                     typeof(TObject),
                     unpackedItems.Concat(unpackItems).Concat(new[] { this.EmitRetrunStatement(context, currentTuple) })
                     ));
        }
Beispiel #8
0
        private static void CreateTupleUnpackFrom(SerializerEmitter emitter, IList <Type> itemTypes)
        {
            var il          = emitter.GetUnpackFromMethodILGenerator();
            var localHolder = new LocalVariableHolder(il);

            try
            {
                /*
                 *  checked
                 *  {
                 *      if (!unpacker.IsArrayHeader)
                 *      {
                 *          throw SerializationExceptions.NewIsNotArrayHeader();
                 *      }
                 *
                 *      if ((int)unpacker.ItemsCount != n)
                 *      {
                 *          throw SerializationExceptions.NewTupleCardinarityIsNotMatch(n, (int)unpacker.ItemsCount);
                 *      }
                 *
                 *		if (!unpacker.Read())
                 *		{
                 *			throw SerializationExceptions.NewMissingItem(0);
                 *		}
                 *
                 *		DESERIALIZE_VALUE
                 *
                 *			:
                 *
                 *		return new Tuple<...>( item1, ... , new Tuple<...>(...)...);
                 *	}
                 */

                il.EmitAnyLdarg(1);
                il.EmitGetProperty(Metadata._Unpacker.IsArrayHeader);
                var endIf = il.DefineLabel("END_IF");
                il.EmitBrtrue_S(endIf);
                il.EmitAnyCall(SerializationExceptions.NewIsNotArrayHeaderMethod);
                il.EmitThrow();
                il.MarkLabel(endIf);

                var itemsCount = localHolder.ItemsCount;
                Emittion.EmitGetUnpackerItemsCountAsInt32(il, 1, localHolder);
                il.EmitAnyLdc_I4(itemTypes.Count);
                il.EmitAnyStloc(itemsCount);
                il.EmitAnyLdloc(itemsCount);
                var endIf1 = il.DefineLabel("END_IF1");
                il.EmitBeq_S(endIf1);
                il.EmitAnyLdc_I4(itemTypes.Count);
                il.EmitAnyLdloc(itemsCount);
                il.EmitAnyCall(SerializationExceptions.NewTupleCardinarityIsNotMatchMethod);
                il.EmitThrow();
                il.MarkLabel(endIf1);

                var itemLocals        = new LocalBuilder[itemTypes.Count];
                var useDummyNullables = new bool[itemTypes.Count];

                for (int i = 0; i < itemTypes.Count; i++)
                {
                    if (itemTypes[i] != typeof(MessagePackObject) &&
                        itemTypes[i].GetIsValueType() &&
                        Nullable.GetUnderlyingType(itemTypes[i]) == null)
                    {
                        // Use temporary nullable value for nil implication.
                        itemLocals[i]        = il.DeclareLocal(typeof(Nullable <>).MakeGenericType(itemTypes[i]), "item" + i.ToString(CultureInfo.InvariantCulture));
                        useDummyNullables[i] = true;
                    }
                    else
                    {
                        itemLocals[i] = il.DeclareLocal(itemTypes[i], "item" + i.ToString(CultureInfo.InvariantCulture));
                    }

                    // Tuple member should be NilImplication.MemberDefault.
                    Emittion.EmitDeserializeValueWithoutNilImplication(emitter, il, 1, itemLocals[i], typeof(Tuple), "Item" + (i).ToString(CultureInfo.InvariantCulture), localHolder);
                }

                for (int i = 0; i < itemLocals.Length; i++)
                {
                    if (useDummyNullables[i])
                    {
                        il.EmitAnyLdloca(itemLocals[i]);
                        il.EmitGetProperty(typeof(Nullable <>).MakeGenericType(itemTypes[i]).GetProperty("Value"));
                    }
                    else
                    {
                        il.EmitAnyLdloc(itemLocals[i]);
                    }
                }

                var tupleTypeList = TupleItems.CreateTupleTypeList(itemTypes);

                for (int depth = tupleTypeList.Count - 1; 0 <= depth; depth--)
                {
                    il.EmitNewobj(tupleTypeList[depth].GetConstructors().Single());
                }

                il.EmitRet();
            }
            finally
            {
                il.FlushTrace();
            }
        }
Beispiel #9
0
        private static void CreateTuplePack(SerializerEmitter emiter, Type tupleType, IList <Type> itemTypes, Action <TracingILGenerator, LocalBuilder> loadTupleEmitter)
        {
            var il          = emiter.GetPackToMethodILGenerator();
            var localHolder = new LocalVariableHolder(il);

            try
            {
                /*
                 * packer.PackArrayHeader( cardinarity );
                 * _serializer0.PackTo( packer, tuple.Item1 );
                 *	:
                 * _serializer6.PackTo( packer, tuple.item7 );
                 * _serializer7.PackTo( packer, tuple.Rest.Item1 );
                 */

                var tuple = il.DeclareLocal(tupleType, "tuple");
                loadTupleEmitter(il, tuple);
                il.EmitAnyLdarg(1);
                il.EmitAnyLdc_I4(itemTypes.Count);
                il.EmitAnyCall(Metadata._Packer.PackArrayHeader);
                il.EmitPop();

                var tupleTypeList = TupleItems.CreateTupleTypeList(itemTypes);

                int depth = -1;
                for (int i = 0; i < itemTypes.Count; i++)
                {
                    if (i % 7 == 0)
                    {
                        depth++;
                    }

                    Emittion.EmitSerializeValue(
                        emiter,
                        il,
                        1,
                        itemTypes[i],
                        null,
                        NilImplication.MemberDefault,
                        il0 =>
                    {
                        il0.EmitAnyLdloc(tuple);

                        for (int j = 0; j < depth; j++)
                        {
                            // .TRest.TRest ...
                            var rest = tupleTypeList[j].GetProperty("Rest");
                            il0.EmitGetProperty(rest);
                        }

                        var itemn = tupleTypeList[depth].GetProperty("Item" + ((i % 7) + 1));
#if DEBUG
                        Contract.Assert(itemn != null, tupleTypeList[depth].GetFullName() + "::Item" + ((i % 7) + 1) + " [ " + depth + " ] @ " + i);
#endif
                        il0.EmitGetProperty(itemn);
                    },
                        localHolder
                        );
                }
                il.EmitRet();
            }
            finally
            {
                il.FlushTrace();
            }
        }
Beispiel #10
0
        private IEnumerable <TConstruct> BuildTuplePackToCore(TContext context, IList <Type> itemTypes, IList <PolymorphismSchema> itemSchemaList, bool isAsync)
        {
            // Note: cardinality is put as array length by PackHelper.
            var depth                   = -1;
            var tupleTypeList           = TupleItems.CreateTupleTypeList(itemTypes);
            var propertyInvocationChain = new List <PropertyInfo>(itemTypes.Count % 7 + 1);
            var packValueArguments      =
                new[] { context.Packer, context.PackToTarget }
#if FEATURE_TAP
            .Concat(isAsync ? new[] { this.ReferCancellationToken(context, 3) } : NoConstructs).ToArray()
#endif // FEATURE_TAP
            ;

            for (int i = 0; i < itemTypes.Count; i++)
            {
                if (i % 7 == 0)
                {
                    depth++;
                }

                for (int j = 0; j < depth; j++)
                {
                    // .TRest.TRest ...
                    var restProperty = tupleTypeList[j].GetProperty("Rest");
#if DEBUG
                    Contract.Assert(restProperty != null);
#endif
                    propertyInvocationChain.Add(restProperty);
                }

                var itemNProperty = tupleTypeList[depth].GetProperty("Item" + ((i % 7) + 1));
                propertyInvocationChain.Add(itemNProperty);
#if DEBUG
                Contract.Assert(
                    itemNProperty != null,
                    tupleTypeList[depth].GetFullName() + "::Item" + ((i % 7) + 1) + " [ " + depth + " ] @ " + i
                    );
#endif
                var count = i;
                DefinePrivateMethod(
                    context,
                    AdjustName(MethodNamePrefix.PackValue + SerializationTarget.GetTupleItemNameFromIndex(i), isAsync),
                    false,                     // isStatic
#if FEATURE_TAP
                    isAsync ? TypeDefinition.TaskType :
#endif // FEATURE_TAP
                    TypeDefinition.VoidType,
                    () => this.EmitSequentialStatements(
                        context,
                        TypeDefinition.VoidType,
                        this.EmitPackTupleItemStatements(
                            context,
                            itemTypes[count],
                            context.Packer,
                            context.PackToTarget,
                            propertyInvocationChain,
                            itemSchemaList.Count == 0 ? null : itemSchemaList[count],
                            isAsync
                            )
                        ),
                    packValueArguments
                    );

                propertyInvocationChain.Clear();
            }

            var packHelperArguments =
                new Dictionary <string, TConstruct>
            {
                { "Packer", context.Packer },
                { "Target", context.PackToTarget },
                { "Operations", this.EmitGetActionsExpression(context, ActionType.PackToArray, isAsync) }
            };

#if FEATURE_TAP
            if (isAsync)
            {
                packHelperArguments.Add("CancellationToken", this.ReferCancellationToken(context, 3));
            }
#endif // FEATURE_TAP

            var packHelperParameterTypeDefinition =
#if FEATURE_TAP
                isAsync ? typeof(PackToArrayAsyncParameters <>) :
#endif // FEATURE_TAP
                typeof(PackToArrayParameters <>);

            var packHelperParameterType =
                TypeDefinition.GenericValueType(packHelperParameterTypeDefinition, this.TargetType);
            var packHelperMethod =
                new MethodDefinition(
                    AdjustName(MethodName.PackToArray, isAsync),
                    new [] { TypeDefinition.Object(this.TargetType) },
                    TypeDefinition.PackHelpersType,
                    true,                             // isStatic
#if FEATURE_TAP
                    isAsync ? TypeDefinition.TaskType :
#endif // FEATURE_TAP
                    TypeDefinition.VoidType,
                    packHelperParameterType
                    );

            var packHelperParameters = this.DeclareLocal(context, packHelperParameterType, "packHelperParameters");
            yield return(packHelperParameters);

            foreach (var construct in this.CreatePackUnpackHelperArgumentInitialization(context, packHelperParameters, packHelperArguments))
            {
                yield return(construct);
            }

            var methodInvocation =
                this.EmitInvokeMethodExpression(
                    context,
                    null,
                    packHelperMethod,
                    this.EmitMakeRef(context, packHelperParameters)
                    );

            if (isAsync)
            {
                // Wrap with return to return Task
                methodInvocation = this.EmitRetrunStatement(context, methodInvocation);
            }

            yield return(methodInvocation);
        }
Beispiel #11
0
        private IEnumerable <TConstruct> BuildTupleUnpackFromCore(TContext context, IList <Type> itemTypes, IList <PolymorphismSchema> itemSchemaList, bool isAsync)
        {
            var tupleTypeList = TupleItems.CreateTupleTypeList(itemTypes);

            yield return
                (this.EmitCheckIsArrayHeaderExpression(context, context.Unpacker));

            yield return
                (this.EmitCheckTupleCardinarityExpression(
                     context,
                     context.Unpacker,
                     itemTypes.Count
                     ));

            var unpackingContext = this.GetTupleUnpackingContextInfo(context, itemTypes);

            foreach (var statement in unpackingContext.Statements)
            {
                yield return(statement);
            }

            var unpackValueArguments =
                new[] { context.Unpacker, context.UnpackingContextInUnpackValueMethods, context.IndexOfItem, context.ItemsCount }
#if FEATURE_TAP
            .Concat(isAsync ? new[] { this.ReferCancellationToken(context, 2) } : NoConstructs).ToArray()
#endif // FEATURE_TAP
            ;

            for (var i = 0; i < itemTypes.Count; i++)
            {
                var propertyName = SerializationTarget.GetTupleItemNameFromIndex(i);
                var unpackedItem = context.DefineUnpackedItemParameterInSetValueMethods(itemTypes[i]);
                var setUnpackValueOfMethodName = MethodNamePrefix.SetUnpackedValueOf + propertyName;

                var index = i;
                this.ExtractPrivateMethod(
                    context,
                    AdjustName(MethodNamePrefix.UnpackValue + propertyName, isAsync),
                    false,                     // isStatic
#if FEATURE_TAP
                    isAsync ? TypeDefinition.TaskType :
#endif // FEATURE_TAP
                    TypeDefinition.VoidType,
                    () => this.EmitUnpackItemValueStatement(
                        context,
                        itemTypes[index],
                        this.MakeStringLiteral(context, propertyName),
                        context.TupleItemNilImplication,
                        null,                         // memberInfo
                        itemSchemaList.Count == 0 ? null : itemSchemaList[index],
                        context.Unpacker,
                        context.UnpackingContextInUnpackValueMethods,
                        context.IndexOfItem,
                        context.ItemsCount,
                        context.IsDeclaredMethod(setUnpackValueOfMethodName)
                                                        ? this.EmitGetPrivateMethodDelegateExpression(
                            context,
                            context.GetDeclaredMethod(setUnpackValueOfMethodName)
                            )
                                                        : this.ExtractPrivateMethod(
                            context,
                            setUnpackValueOfMethodName,
                            false,                                     // isStatic
                            TypeDefinition.VoidType,
                            () => unpackingContext.VariableType.TryGetRuntimeType() == typeof(DynamicUnpackingContext)
                                                                        ? this.EmitInvokeVoidMethod(
                                context,
                                context.UnpackingContextInSetValueMethods,
                                Metadata._DynamicUnpackingContext.Set,
                                this.MakeStringLiteral(context, propertyName),
                                this.EmitBoxExpression(
                                    context,
                                    itemTypes[index],
                                    unpackedItem
                                    )
                                ) : this.EmitSetField(
                                context,
                                context.UnpackingContextInSetValueMethods,
                                unpackingContext.VariableType,
                                propertyName,
                                unpackedItem
                                ),
                            context.UnpackingContextInSetValueMethods,
                            unpackedItem
                            ),
                        isAsync
                        ),
                    unpackValueArguments
                    );
            }

            TConstruct currentTuple = null;
            for (int nest = tupleTypeList.Count - 1; nest >= 0; nest--)
            {
                var gets =
                    Enumerable.Range(nest * 7, Math.Min(itemTypes.Count - nest * 7, 7))
                    .Select(i =>
                            unpackingContext.VariableType.TryGetRuntimeType() == typeof(DynamicUnpackingContext)
                                                                ? this.EmitUnboxAnyExpression(
                                context,
                                itemTypes[i],
                                this.EmitInvokeMethodExpression(
                                    context,
                                    context.UnpackingContextInCreateObjectFromContext,
                                    Metadata._DynamicUnpackingContext.Get,
                                    this.MakeStringLiteral(context, SerializationTarget.GetTupleItemNameFromIndex(i))
                                    )
                                ) : this.EmitGetFieldExpression(
                                context,
                                context.UnpackingContextInCreateObjectFromContext,
                                new FieldDefinition(
                                    unpackingContext.VariableType,
                                    SerializationTarget.GetTupleItemNameFromIndex(i),
                                    itemTypes[i]
                                    )
                                )
                            );
                if (currentTuple != null)
                {
                    gets = gets.Concat(new[] { currentTuple });
                }

                currentTuple =
                    this.EmitCreateNewObjectExpression(
                        context,
                        null,                         // Tuple is reference contextType.
                        tupleTypeList[nest].GetConstructors().Single(),
                        gets.ToArray()
                        );
            }

#if DEBUG
            Contract.Assert(currentTuple != null);
#endif
            unpackingContext.Factory =
                this.EmitNewPrivateMethodDelegateExpressionWithCreation(
                    context,
                    new MethodDefinition(
                        MethodName.CreateObjectFromContext,
                        null,
                        null,
                        true,                         // isStatic
                        this.TargetType,
                        unpackingContext.Type
                        ),
                    () => this.EmitRetrunStatement(
                        context,
                        currentTuple
                        ),
                    context.UnpackingContextInCreateObjectFromContext
                    );


            var unpackHelperArguments =
                new[]
            {
                context.Unpacker,
                unpackingContext.Variable,
                unpackingContext.Factory,
                this.EmitGetMemberNamesExpression(context),
                this.EmitGetActionsExpression(context, ActionType.UnpackFromArray, isAsync)
            }
#if FEATURE_TAP
            .Concat(isAsync ? new[] { this.ReferCancellationToken(context, 2) } : NoConstructs).ToArray()
#endif // FEATURE_TAP
            ;

            yield return
                (this.EmitRetrunStatement(
                     context,
                     this.EmitInvokeMethodExpression(
                         context,
                         null,
                         new MethodDefinition(
                             AdjustName(MethodName.UnpackFromArray, isAsync),
                             new [] { unpackingContext.Type, this.TargetType },
                             TypeDefinition.UnpackHelpersType,
                             true,                            // isStatic
#if FEATURE_TAP
                             isAsync ? typeof(Task <>).MakeGenericType(this.TargetType) :
#endif // FEATURE_TAP
                             this.TargetType,
                             unpackHelperArguments.Select(a => a.ContextType).ToArray()
                             ),
                         unpackHelperArguments
                         )
                     ));
        }
        private IEnumerable <TConstruct> BuildTuplePackToCore(TContext context, IList <Type> itemTypes, IList <PolymorphismSchema> itemSchemaList, bool isAsync)
        {
            // Note: cardinality is put as array length by PackHelper.
            var depth                   = -1;
            var tupleTypeList           = TupleItems.CreateTupleTypeList(itemTypes);
            var propertyInvocationChain = new List <PropertyInfo>(itemTypes.Count % 7 + 1);
            var packValueArguments      =
                new[] { context.Packer, context.PackToTarget }
#if FEATURE_TAP
            .Concat(isAsync ? new[] { this.ReferCancellationToken(context, 3) } : NoConstructs).ToArray()
#endif // FEATURE_TAP
            ;

            for (int i = 0; i < itemTypes.Count; i++)
            {
                if (i % 7 == 0)
                {
                    depth++;
                }

                for (int j = 0; j < depth; j++)
                {
                    // .TRest.TRest ...
                    var restProperty = tupleTypeList[j].GetProperty("Rest");
#if DEBUG
                    Contract.Assert(restProperty != null);
#endif
                    propertyInvocationChain.Add(restProperty);
                }

                var itemNProperty = tupleTypeList[depth].GetProperty("Item" + ((i % 7) + 1));
                propertyInvocationChain.Add(itemNProperty);
#if DEBUG
                Contract.Assert(
                    itemNProperty != null,
                    tupleTypeList[depth].GetFullName() + "::Item" + ((i % 7) + 1) + " [ " + depth + " ] @ " + i
                    );
#endif
                var count = i;
                this.ExtractPrivateMethod(
                    context,
                    AdjustName(MethodNamePrefix.PackValue + SerializationTarget.GetTupleItemNameFromIndex(i), isAsync),
#if FEATURE_TAP
                    isAsync ? typeof(Task) :
#endif // FEATURE_TAP
                    typeof(void),
                    () => this.EmitSequentialStatements(
                        context,
                        typeof(void),
                        this.EmitPackTupleItemStatements(
                            context,
                            itemTypes[count],
                            context.Packer,
                            context.PackToTarget,
                            propertyInvocationChain,
                            itemSchemaList.Count == 0 ? null : itemSchemaList[count],
                            isAsync
                            )
                        ),
                    packValueArguments
                    );

                propertyInvocationChain.Clear();
            }

            var packHelperArguments =
                new[]
            {
                context.Packer,
                context.PackToTarget,
                this.EmitGetActionsExpression(context, ActionType.PackToArray, isAsync)
            }
#if FEATURE_TAP
            .Concat(isAsync ? new[] { this.ReferCancellationToken(context, 3) } : NoConstructs).ToArray()
#endif // FEATURE_TAP
            ;

            var packToArray =
                this.EmitInvokeMethodExpression(
                    context,
                    null,
                    new MethodDefinition(
                        AdjustName(MethodName.PackToArray, isAsync),
                        new [] { TypeDefinition.Object(this.TargetType) },
                        typeof(PackHelpers),
#if FEATURE_TAP
                        isAsync ? typeof(Task) :
#endif // FEATURE_TAP
                        typeof(void),
                        packHelperArguments.Select(a => a.ContextType).ToArray()
                        ),
                    packHelperArguments
                    );

            if (isAsync)
            {
                // Wrap with return to return Task
                packToArray = this.EmitRetrunStatement(context, packToArray);
            }

            yield return(packToArray);
        }