Пример #1
0
        public static void GetMetadata(
            IList <SerializingMember> members,
            SerializationContext context,
            out Func <object, object>[] getters,
            out Action <object, object>[] setters,
            out MemberInfo[] memberInfos,
            out DataMemberContract[] contracts,
            out IMessagePackSerializer[] serializers)
        {
            getters     = new Func <object, object> [members.Count];
            setters     = new Action <object, object> [members.Count];
            memberInfos = new MemberInfo[members.Count];
            contracts   = new DataMemberContract[members.Count];
            serializers = new IMessagePackSerializer[members.Count];

            for (var i = 0; i < members.Count; i++)
            {
                var member = members[i];
                if (member.Member == null)
                {
#if UNITY
                    contracts[i] = DataMemberContract.Null;
#endif // UNITY
                    continue;
                }

                FieldInfo asField;
                if ((asField = member.Member as FieldInfo) != null)
                {
                    getters[i] = asField.GetValue;
                    setters[i] = asField.SetValue;
                }
                else
                {
                    var property = member.Member as PropertyInfo;
#if DEBUG && !UNITY
                    Contract.Assert(property != null, "member.Member is PropertyInfo");
#endif // DEBUG && !UNITY
                    getters[i] = target => property.GetGetMethod(true).InvokePreservingExceptionType(target, null);
                    var setter = property.GetSetMethod(true);
                    if (setter != null)
                    {
                        setters[i] = (target, value) => setter.InvokePreservingExceptionType(target, new[] { value });
                    }
                }

                memberInfos[i] = member.Member;
#if !UNITY
                contracts[i] = member.Contract;
#else
                contracts[i] = member.Contract ?? DataMemberContract.Null;
#endif // !UNITY
                var memberType = member.Member.GetMemberValueType();
                if (memberType.GetIsEnum())
                {
                    serializers[i] =
                        context.GetSerializer(
                            memberType,
                            EnumMessagePackSerializerHelpers.DetermineEnumSerializationMethod(
                                context,
                                memberType,
                                member.GetEnumMemberSerializationMethod()
                                )
                            );
                }
                else if (DateTimeMessagePackSerializerHelpers.IsDateTime(memberType))
                {
                    serializers[i] =
                        context.GetSerializer(
                            memberType,
                            DateTimeMessagePackSerializerHelpers.DetermineDateTimeConversionMethod(
                                context,
                                member.GetDateTimeMemberConversionMethod()
                                )
                            );
                }
                else
                {
                    serializers[i] = context.GetSerializer(memberType, PolymorphismSchema.Create(context, memberType, member));
                }
            }
        }
        public override Func <SerializationContext, PolymorphismSchema, MessagePackSerializer <T> > CreateConstructor <T>()
        {
            if (!this._typeBuilder.IsCreated())
            {
                /*
                 *	.ctor() : this(null)
                 *	{}
                 */
                /*
                 *	.ctor( SerializationContext context )
                 *	  : base( ( context ?? SerializationContext.Default ).CompabilityOptions.PackerCompatibilityOptions )
                 *	{
                 *		this._serializer0 = context.GetSerializer<T0>();
                 *		this._serializer1 = context.GetSerializer<T1>();
                 *		this._serializer2 = context.GetSerializer<T2>();
                 *			:
                 *	}
                 */
                // default
                {
                    var il = this._defaultConstructorBuilder.GetILGenerator();
                    // : this(null)
                    il.Emit(OpCodes.Ldarg_0);
                    il.Emit(OpCodes.Ldnull);
                    il.Emit(OpCodes.Call, this._contextConstructorBuilder);
                    il.Emit(OpCodes.Ret);
                }

                // context
                {
                    var il = new TracingILGenerator(this._contextConstructorBuilder, TextWriter.Null, this._isDebuggable);
                    // : base()
                    il.EmitLdarg_0();
                    il.EmitLdarg_1();
#if DEBUG
                    Contract.Assert(this._typeBuilder.BaseType != null, "this._typeBuilder.BaseType != null");
#endif
                    if (this._traits.CollectionType == CollectionKind.NotCollection)
                    {
                        il.EmitCallConstructor(
                            this._typeBuilder.BaseType.GetConstructor(
                                BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, ConstructorParameterTypes, null
                                )
                            );
                    }
                    else
                    {
                        il.EmitCall(this._restoreSchemaMethodBuilder);
                        il.EmitCallConstructor(
                            this._typeBuilder.BaseType.GetConstructor(
                                BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, CollectionConstructorParameterTypes, null
                                )
                            );
                    }

                    // this._serializerN = context.GetSerializer<T>();
                    foreach (var entry in this._serializers)
                    {
                        var        targetType = Type.GetTypeFromHandle(entry.Key.TypeHandle);
                        MethodInfo getMethod  = Metadata._SerializationContext.GetSerializer1_Parameter_Method.MakeGenericMethod(targetType);

                        il.EmitLdarg_0();
                        il.EmitLdarg_1();
                        if (targetType.GetIsEnum())
                        {
                            il.EmitLdarg_1();
                            il.EmitTypeOf(targetType);
                            il.EmitAnyLdc_I4(( int )entry.Key.EnumSerializationMethod);
                            il.EmitCall(Metadata._EnumMessagePackSerializerHelpers.DetermineEnumSerializationMethodMethod);
                            il.EmitBox(typeof(EnumSerializationMethod));
                        }
                        else if (DateTimeMessagePackSerializerHelpers.IsDateTime(targetType))
                        {
                            il.EmitLdarg_1();
                            il.EmitAnyLdc_I4(( int )entry.Key.DateTimeConversionMethod);
                            il.EmitCall(Metadata._DateTimeMessagePackSerializerHelpers.DetermineDateTimeConversionMethodMethod);
                            il.EmitBox(typeof(DateTimeConversionMethod));
                        }
                        else
                        {
                            if (entry.Key.PolymorphismSchema == null)
                            {
                                il.EmitLdnull();
                            }
                            else
                            {
                                entry.Value.SchemaProvider(il);
                            }
                        }

                        il.EmitCallvirt(getMethod);
                        il.EmitStfld(entry.Value.Field);
                    }

                    foreach (var entry in this._fieldInfos)
                    {
                        il.EmitLdarg_0();
                        il.EmitLdtoken(FieldInfo.GetFieldFromHandle(entry.Key));
                        il.EmitCall(Metadata._FieldInfo.GetFieldFromHandle);
                        il.EmitStfld(entry.Value);
                    }

                    foreach (var entry in this._methodBases)
                    {
                        il.EmitLdarg_0();
                        il.EmitLdtoken(MethodBase.GetMethodFromHandle(entry.Key));
                        il.EmitCall(Metadata._MethodBase.GetMethodFromHandle);
                        il.EmitStfld(entry.Value);
                    }

                    il.EmitRet();
                }
            }

            var ctor             = this._typeBuilder.CreateType().GetConstructor(ConstructorParameterTypes);
            var contextParameter = Expression.Parameter(typeof(SerializationContext), "context");
            var schemaParameter  = Expression.Parameter(typeof(PolymorphismSchema), "schema");
#if DEBUG
            Contract.Assert(ctor != null, "ctor != null");
#endif
            return
                (Expression.Lambda <Func <SerializationContext, PolymorphismSchema, MessagePackSerializer <T> > >(
                     Expression.New(
                         ctor,
                         contextParameter
                         ),
                     contextParameter,
                     schemaParameter
                     ).Compile());
        }
        public static void GetMetadata(
            Type targetType,
            IList <SerializingMember> members,
            SerializationContext context,
            out Func <object, object>[] getters,
            out Action <object, object>[] setters,
            out MemberInfo[] memberInfos,
            out DataMemberContract[] contracts,
            out MessagePackSerializer[] serializers
            )
        {
            SerializationTarget.VerifyCanSerializeTargetType(context, targetType);

            if (members.Count == 0)
            {
                if (!typeof(IPackable).IsAssignableFrom(targetType))
                {
                    throw new SerializationException(
                              String.Format(
                                  CultureInfo.CurrentCulture,
                                  "At least one serializable member is required because type '{0}' does not implement IPackable interface.",
                                  targetType
                                  )
                              );
                }

                if (!typeof(IUnpackable).IsAssignableFrom(targetType))
                {
                    throw new SerializationException(
                              String.Format(
                                  CultureInfo.CurrentCulture,
                                  "At least one serializable member is required because type '{0}' does not implement IUnpackable interface.",
                                  targetType
                                  )
                              );
                }

#if FEATURE_TAP
                if (context.SerializerOptions.WithAsync)
                {
                    if (!typeof(IAsyncPackable).IsAssignableFrom(targetType))
                    {
                        throw new SerializationException(
                                  String.Format(
                                      CultureInfo.CurrentCulture,
                                      "At least one serializable member is required because type '{0}' does not implement IAsyncPackable interface.",
                                      targetType
                                      )
                                  );
                    }

                    if (!typeof(IAsyncUnpackable).IsAssignableFrom(targetType))
                    {
                        throw new SerializationException(
                                  String.Format(
                                      CultureInfo.CurrentCulture,
                                      "At least one serializable member is required because type '{0}' does not implement IAsyncUnpackable interface.",
                                      targetType
                                      )
                                  );
                    }
                }
#endif // FEATURE_TAP
            }

            getters     = new Func <object, object> [members.Count];
            setters     = new Action <object, object> [members.Count];
            memberInfos = new MemberInfo[members.Count];
            contracts   = new DataMemberContract[members.Count];
            serializers = new MessagePackSerializer[members.Count];

            for (var i = 0; i < members.Count; i++)
            {
                var member = members[i];

                if (member.Member == null)
                {
                    // Missing member exist because of unconbinous Id of MessagePackMember or Order of DataMember.
#if UNITY
                    contracts[i] = DataMemberContract.Null;
#endif // UNITY
                    continue;
                }

                FieldInfo asField;
                if ((asField = member.Member as FieldInfo) != null)
                {
                    if (context.SerializerOptions.DisablePrivilegedAccess && !asField.GetIsPublic())
                    {
                        continue;
                    }

                    getters[i] = asField.GetValue;
                    if (!asField.IsInitOnly)
                    {
                        setters[i] = asField.SetValue;
                    }
                }
                else
                {
                    var property = member.Member as PropertyInfo;
#if DEBUG
                    Contract.Assert(property != null, "member.Member is PropertyInfo");
#endif // DEBUG
                    if (context.SerializerOptions.DisablePrivilegedAccess && !property.GetIsPublic())
                    {
                        continue;
                    }

                    var getter = property.GetGetMethod(true);
                    if (getter == null)
                    {
                        ThrowMissingGetterException(targetType, i, property);
                    }

                    getters[i] = target => getter.InvokePreservingExceptionType(target, null);
                    var setter = property.GetSetMethod(true);
                    if (setter != null && (!context.SerializerOptions.DisablePrivilegedAccess || setter.GetIsPublic()))
                    {
                        setters[i] = (target, value) => setter.InvokePreservingExceptionType(target, new[] { value });
                    }
                }

                memberInfos[i] = member.Member;
#if !UNITY
                contracts[i] = member.Contract;
#else
                contracts[i] = member.Contract ?? DataMemberContract.Null;
#endif // !UNITY
                var memberType = member.Member.GetMemberValueType();
                if (memberType.GetIsEnum())
                {
                    serializers[i] =
                        context.GetSerializer(
                            memberType,
                            EnumMessagePackSerializerHelpers.DetermineEnumSerializationMethod(
                                context,
                                memberType,
                                member.GetEnumMemberSerializationMethod()
                                )
                            );
                }
                else if (DateTimeMessagePackSerializerHelpers.IsDateTime(memberType))
                {
                    serializers[i] =
                        context.GetSerializer(
                            memberType,
                            DateTimeMessagePackSerializerHelpers.DetermineDateTimeConversionMethod(
                                context,
                                member.GetDateTimeMemberConversionMethod()
                                )
                            );
                }
                else
                {
                    serializers[i] = context.GetSerializer(memberType, PolymorphismSchema.Create(memberType, member));
                }
            }
        }
        private void CreateContextfulObjectConstructor(
            AssemblyBuilderEmittingContext context,
            Type baseType,
            TracingILGenerator il,
            Func <ILConstruct> packActionListInitializerProvider,
            Func <ILConstruct> packActionTableInitializerProvider,
            Func <ILConstruct> unpackActionListInitializerProvider,
            Func <ILConstruct> unpackActionTableInitializerProvider,
#if FEATURE_TAP
            Func <ILConstruct> packAsyncActionListInitializerProvider,
            Func <ILConstruct> packAsyncActionTableInitializerProvider,
            Func <ILConstruct> unpackAsyncActionListInitializerProvider,
            Func <ILConstruct> unpackAsyncActionTableInitializerProvider,
#endif // FEATURE_TAP
            Func <ILConstruct> memberNamesInitializerProvider,
            Func <ILConstruct> unpackToInitializerProvider
            )
        {
            /*
             *	.ctor( SerializationContext context )
             *	  : base( ( context ?? SerializationContext.Default ).CompabilityOptions.PackerCompatibilityOptions )
             *	{
             *		this._serializer0 = context.GetSerializer<T0>();
             *		this._serializer1 = context.GetSerializer<T1>();
             *		this._serializer2 = context.GetSerializer<T2>();
             *			:
             *	}
             */
            // : base()
            il.EmitLdarg_0();
            il.EmitLdarg_1();
            if (this._specification.TargetCollectionTraits.CollectionType == CollectionKind.NotCollection)
            {
                il.EmitCallConstructor(
                    baseType.GetRuntimeConstructor(ConstructorParameterTypes)
                    );
            }
            else
            {
                il.EmitCall(this._methodTable[MethodName.RestoreSchema]);
                il.EmitCallConstructor(
                    baseType.GetRuntimeConstructor(CollectionConstructorParameterTypes)
                    );
            }

            // this._serializerN = context.GetSerializer<T>();
            foreach (var entry in this._serializers)
            {
                var        targetType = Type.GetTypeFromHandle(entry.Key.TypeHandle);
                MethodInfo getMethod  = Metadata._SerializationContext.GetSerializer1_Parameter_Method.MakeGenericMethod(targetType);

                il.EmitLdarg_0();
                il.EmitLdarg_1();
                if (targetType.GetIsEnum())
                {
                    il.EmitLdarg_1();
                    il.EmitTypeOf(targetType);
                    il.EmitAnyLdc_I4(( int )entry.Key.EnumSerializationMethod);
                    il.EmitCall(Metadata._EnumMessagePackSerializerHelpers.DetermineEnumSerializationMethodMethod);
                    il.EmitBox(typeof(EnumSerializationMethod));
                }
                else if (DateTimeMessagePackSerializerHelpers.IsDateTime(targetType))
                {
                    il.EmitLdarg_1();
                    il.EmitAnyLdc_I4(( int )entry.Key.DateTimeConversionMethod);
                    il.EmitCall(Metadata._DateTimeMessagePackSerializerHelpers.DetermineDateTimeConversionMethodMethod);
                    il.EmitBox(typeof(DateTimeConversionMethod));
                }
                else
                {
                    if (entry.Key.PolymorphismSchema == null)
                    {
                        il.EmitLdnull();
                    }
                    else
                    {
                        entry.Value.SchemaProvider(il);
                    }
                }

                il.EmitCallvirt(getMethod);
                il.EmitStfld(entry.Value.Field);
            }

            foreach (var entry in this._cachedFieldInfos)
            {
                il.EmitLdarg_0();
                il.EmitLdtoken(entry.Value.Target);
                il.EmitLdtoken(entry.Value.Target.DeclaringType);
                il.EmitCall(Metadata._FieldInfo.GetFieldFromHandle);
                il.EmitStfld(entry.Value.StorageFieldBuilder);
            }

            foreach (var entry in this._cachedMethodBases)
            {
                il.EmitLdarg_0();
                il.EmitLdtoken(entry.Value.Target);
                il.EmitLdtoken(entry.Value.Target.DeclaringType);
                il.EmitCall(Metadata._MethodBase.GetMethodFromHandle);
                il.EmitStfld(entry.Value.StorageFieldBuilder);
            }

            if (packActionListInitializerProvider != null)
            {
                packActionListInitializerProvider().Evaluate(il);
            }

#if FEATURE_TAP
            if (packAsyncActionListInitializerProvider != null)
            {
                packAsyncActionListInitializerProvider().Evaluate(il);
            }
#endif // FEATURE_TAP

            if (packActionTableInitializerProvider != null)
            {
                packActionTableInitializerProvider().Evaluate(il);
            }

#if FEATURE_TAP
            if (packAsyncActionTableInitializerProvider != null)
            {
                packAsyncActionTableInitializerProvider().Evaluate(il);
            }
#endif // FEATURE_TAP

            if (unpackActionListInitializerProvider != null)
            {
                unpackActionListInitializerProvider().Evaluate(il);
            }

#if FEATURE_TAP
            if (unpackAsyncActionListInitializerProvider != null)
            {
                unpackAsyncActionListInitializerProvider().Evaluate(il);
            }
#endif // FEATURE_TAP

            if (unpackActionTableInitializerProvider != null)
            {
                unpackActionTableInitializerProvider().Evaluate(il);
            }

#if FEATURE_TAP
            if (unpackAsyncActionTableInitializerProvider != null)
            {
                unpackAsyncActionTableInitializerProvider().Evaluate(il);
            }
#endif // FEATURE_TAP

            if (memberNamesInitializerProvider != null)
            {
                memberNamesInitializerProvider().Evaluate(il);
            }

            if (unpackToInitializerProvider != null)
            {
                unpackToInitializerProvider().Evaluate(il);
            }

            foreach (var cachedDelegateInfo in context.GetCachedDelegateInfos())
            {
                // this for stfld
                il.EmitLdargThis();

                var delegateType = cachedDelegateInfo.BackingField.FieldType.ResolveRuntimeType();

                // Declare backing field now.
                var field = context.GetDeclaredField(cachedDelegateInfo.BackingField.FieldName).ResolveRuntimeField();

                if (cachedDelegateInfo.IsThisInstance)
                {
                    il.EmitLdargThis();
                }
                else
                {
                    il.EmitLdnull();
                }

                // OK this should not be ldvirtftn because target is private or static.
                il.EmitLdftn(cachedDelegateInfo.TargetMethod.ResolveRuntimeMethod());
                // call extern .ctor(Object, void*)
                il.EmitNewobj(delegateType.GetConstructors().Single());

                il.EmitStfld(field);
            }

            il.EmitRet();
        }