public MessagePackSerializer <TObject> BuildSerializerInstance(SerializationContext context) { var genericSerializer = GenericSerializer.Create <TObject>(context); if (genericSerializer != null) { return(genericSerializer); } var codeGenerationContext = this.CreateCodeGenerationContextForSerializerCreation(context); if (typeof(TObject).GetIsEnum()) { this.BuildEnumSerializer(codeGenerationContext); Func <SerializationContext, MessagePackSerializer <TObject> > constructor = this.CreateEnumSerializerConstructor(codeGenerationContext); if (constructor != null) { var serializer = constructor(context); #if DEBUG Contract.Assert(serializer != null); #endif if (!context.Serializers.Register(serializer)) { serializer = context.Serializers.Get <TObject>(context); #if DEBUG Contract.Assert(serializer != null); #endif } return(serializer); } } else { this.BuildSerializer(codeGenerationContext); Func <SerializationContext, MessagePackSerializer <TObject> > constructor = this.CreateSerializerConstructor(codeGenerationContext); if (constructor != null) { var serializer = constructor(context); #if DEBUG Contract.Assert(serializer != null); #endif if (!context.Serializers.Register(serializer)) { serializer = context.Serializers.Get <TObject>(context); #if DEBUG Contract.Assert(serializer != null); #endif } return(serializer); } } throw SerializationExceptions.NewTypeCannotSerialize(typeof(TObject)); }
/// <summary> /// Gets the <see cref="MessagePackSerializer{T}"/> with this instance. /// </summary> /// <typeparam name="T">Type of serialization/deserialization target.</typeparam> /// <param name="providerParameter">A provider specific parameter. See remarks section for details.</param> /// <returns> /// <see cref="MessagePackSerializer{T}"/>. /// If there is exiting one, returns it. /// Else the new instance will be created. /// </returns> /// <remarks> /// <para> /// This method automatically register new instance via <see cref="SerializerRepository.Register{T}(MessagePackSerializer{T})"/>. /// </para> /// <para> /// Currently, only following provider parameters are supported. /// <list type="table"> /// <listheader> /// <term>Target type</term> /// <description>Provider parameter</description> /// </listheader> /// <item> /// <term><see cref="EnumMessagePackSerializer{TEnum}"/> or its descendants.</term> /// <description><see cref="EnumSerializationMethod"/>. The returning instance corresponds to this value for serialization.</description> /// </item> /// </list> /// <note><c>null</c> is valid value for <paramref name="providerParameter"/> and it indeicates default behavior of parameter.</note> /// </para> /// </remarks> public MessagePackSerializer<T> GetSerializer<T>( object providerParameter ) { #if !UNITY Contract.Ensures( Contract.Result<MessagePackSerializer<T>>() != null ); #endif // !UNITY var schema = providerParameter as PolymorphismSchema; // Explicitly generated serializer should always used, so get it first. MessagePackSerializer<T> serializer = this._serializers.Get<T>( this, providerParameter ); if ( serializer != null ) { return serializer; } object aquiredLock = null; bool lockTaken = false; try { try { } finally { var newLock = new object(); #if SILVERLIGHT || NETFX_35 || UNITY Monitor.Enter( newLock ); try { lock ( this._typeLock ) { lockTaken = !this._typeLock.TryGetValue( typeof( T ), out aquiredLock ); if ( lockTaken ) { aquiredLock = newLock; this._typeLock.Add( typeof( T ), newLock ); } } #else bool newLockTaken = false; try { Monitor.Enter( newLock, ref newLockTaken ); aquiredLock = this._typeLock.GetOrAdd( typeof( T ), _ => newLock ); lockTaken = newLock == aquiredLock; #endif // if SILVERLIGHT || NETFX_35 || UNITY } finally { #if SILVERLIGHT || NETFX_35 || UNITY if ( !lockTaken ) #else if ( !lockTaken && newLockTaken ) #endif // if SILVERLIGHT || NETFX_35 || UNITY { // Release the lock which failed to become 'primary' lock. Monitor.Exit( newLock ); } } } if ( Monitor.TryEnter( aquiredLock ) ) { // Decrement monitor counter. Monitor.Exit( aquiredLock ); #if DEBUG && !NETFX_40 && !NETFX_35 && !SILVERLIGHT && !UNITY Contract.Assert( Monitor.IsEntered( aquiredLock ), "Monitor.IsEntered(aquiredLock)" ); #endif // DEBUG && !NETFX_40 && !NETFX_35 !SILVERLIGHT && && !UNITY if ( lockTaken ) { // First try to create generic serializer w/o code generation. serializer = GenericSerializer.Create<T>( this, schema ); if ( serializer == null ) { #if !XAMIOS && !XAMDROID && !UNITY if ( this.IsRuntimeGenerationDisabled ) { #endif // !XAMIOS && !XAMDROID && !UNITY // On debugging, or AOT only envs, use reflection based aproach. serializer = this.GetSerializerWithoutGeneration<T>( schema ) ?? this.OnResolveSerializer<T>( schema ) ?? MessagePackSerializer.CreateReflectionInternal<T>( this, this.EnsureConcreteTypeRegistered( typeof( T ) ), schema ); #if !XAMIOS && !XAMDROID && !UNITY } else { // This thread creating new type serializer. serializer = this.OnResolveSerializer<T>( schema ) ?? MessagePackSerializer.CreateInternal<T>( this, schema ); } #endif // !XAMIOS && !XAMDROID && !UNITY } } else { // This thread owns existing lock -- thus, constructing self-composite type. // Prevent release owned lock. aquiredLock = null; return new LazyDelegatingMessagePackSerializer<T>( this, providerParameter ); } // Some types always have to use provider. MessagePackSerializerProvider provider; var asEnumSerializer = serializer as ICustomizableEnumSerializer; if ( asEnumSerializer != null ) { #if DEBUG && !UNITY Contract.Assert( typeof( T ).GetIsEnum(), typeof( T ) + " is not enum but generated serializer is ICustomizableEnumSerializer" ); #endif // DEBUG && !UNITY provider = new EnumMessagePackSerializerProvider( typeof( T ), asEnumSerializer ); } else { #if DEBUG && !UNITY Contract.Assert( !typeof( T ).GetIsEnum(), typeof( T ) + " is enum but generated serializer is not ICustomizableEnumSerializer : " + ( serializer == null ? "null" : serializer.GetType().FullName ) ); #endif // DEBUG && !UNITY // Creates provider even if no schema -- the schema might be specified future for the type. // It is OK to use polymorphic provider for value type. #if !UNITY provider = new PolymorphicSerializerProvider<T>( serializer ); #else provider = new PolymorphicSerializerProvider<T>( this, serializer ); #endif // !UNITY } #if !UNITY Type nullableType; MessagePackSerializerProvider nullableSerializerProvider; SerializerRepository.GetNullableCompanion( typeof( T ), this, serializer, out nullableType, out nullableSerializerProvider ); this._serializers.Register( typeof( T ), provider, nullableType, nullableSerializerProvider, SerializerRegistrationOptions.WithNullable ); #else this._serializers.Register( typeof( T ), provider, null, null, SerializerRegistrationOptions.None ); #endif // !UNITY } else { // Wait creation by other thread. // Acquire as 'waiting' lock. Monitor.Enter( aquiredLock ); } // Re-get to avoid duplicated registration and handle provider parameter or get the one created by prececing thread. // If T is null and schema is not provided or default schema is provided, then exception will be thrown here from the new provider. return this._serializers.Get<T>( this, providerParameter ); } finally { if ( lockTaken ) { #if SILVERLIGHT || NETFX_35 || UNITY lock ( this._typeLock ) { this._typeLock.Remove( typeof( T ) ); } #else object dummy; this._typeLock.TryRemove( typeof( T ), out dummy ); #endif // if SILVERLIGHT || NETFX_35 || UNITY } if ( aquiredLock != null ) { // Release primary lock or waiting lock. Monitor.Exit( aquiredLock ); #if DEBUG && !NETFX_40 && !NETFX_35 && !SILVERLIGHT && !UNITY Contract.Assert( !Monitor.IsEntered( aquiredLock ), "!Monitor.IsEntered(aquiredLock)" ); #endif // DEBUG && !NETFX_40 && !NETFX_35 && !SILVERLIGHT && !UNITY } } }
/// <summary> /// Gets the serializer for the specified <see cref="Type"/>. /// </summary> /// <param name="targetType">Type of the serialization target.</param> /// <param name="providerParameter">A provider specific parameter. See remarks section of <see cref="GetSerializer{T}(Object)"/> for details.</param> /// <returns> /// <see cref="IMessagePackSingleObjectSerializer"/>. /// If there is exiting one, returns it. /// Else the new instance will be created. /// </returns> /// <exception cref="ArgumentNullException"> /// <paramref name="targetType"/> is <c>null</c>. /// </exception> /// <remarks> /// Although <see cref="GetSerializer{T}(Object)"/> is preferred, /// this method can be used from non-generic type or methods. /// </remarks> public IMessagePackSingleObjectSerializer GetSerializer(Type targetType, object providerParameter) { if (targetType == null) { throw new ArgumentNullException("targetType"); } #if !UNITY Contract.Ensures(Contract.Result <IMessagePackSerializer>() != null); #endif // !UNITY #if !XAMIOS && !XAMDROID && !UNITY return(SerializerGetter.Instance.Get(this, targetType, providerParameter)); #else var serializer = this._serializers.Get(this, targetType, providerParameter) ?? GenericSerializer.Create(this, targetType); if (serializer == null) { serializer = this.GetSerializerWithoutGeneration(targetType) as IMessagePackSingleObjectSerializer ?? MessagePackSerializer.CreateReflectionInternal(this, targetType); } if (!this._serializers.Register(targetType, serializer) || providerParameter != null) { // Re-get to avoid duplicated registration and handle provider parameter. serializer = this._serializers.Get(this, targetType, providerParameter); } return(serializer); #endif // !XAMIOS && !XAMDROID && !UNITY }
/// <summary> /// Gets the <see cref="MessagePackSerializer{T}"/> with this instance. /// </summary> /// <typeparam name="T">Type of serialization/deserialization target.</typeparam> /// <param name="providerParameter">A provider specific parameter. See remarks section for details.</param> /// <returns> /// <see cref="MessagePackSerializer{T}"/>. /// If there is exiting one, returns it. /// Else the new instance will be created. /// </returns> /// <remarks> /// <para> /// This method automatically register new instance via <see cref="SerializerRepository.Register{T}(MessagePackSerializer{T})"/>. /// </para> /// <para> /// Currently, only following provider parameters are supported. /// <list type="table"> /// <listheader> /// <term>Target type</term> /// <description>Provider parameter</description> /// </listheader> /// <item> /// <term><see cref="EnumMessagePackSerializer{TEnum}"/> or its descendants.</term> /// <description><see cref="EnumSerializationMethod"/>. The returning instance corresponds to this value for serialization.</description> /// </item> /// </list> /// <note><c>null</c> is valid value for <paramref name="providerParameter"/> and it indeicates default behavior of parameter.</note> /// </para> /// </remarks> public MessagePackSerializer<T> GetSerializer<T>( object providerParameter ) { #if DEBUG Contract.Ensures( Contract.Result<MessagePackSerializer<T>>() != null ); #endif // DEBUG // Explicitly generated serializer should always used, so get it first. MessagePackSerializer<T> serializer = this._serializers.Get<T>( this, providerParameter ); if ( serializer != null ) { return serializer; } bool lockTaken = false; lock ( this._generationLock ) { // Re-get to check because other thread might create the serializer when I wait the lock. serializer = this._serializers.Get<T>( this, providerParameter ); if ( serializer != null ) { return serializer; } try { try { } finally { #if !FEATURE_CONCURRENT lock ( this._typeLock ) { var typeLock = new object(); object aquiredLock; lockTaken = !this._typeLock.TryGetValue( typeof( T ), out aquiredLock ); if ( lockTaken ) { this._typeLock.Add( typeof( T ), typeLock ); } } #else var typeLock = new object(); var aquiredTypeLock = this._typeLock.GetOrAdd( typeof( T ), _ => typeLock ); lockTaken = typeLock == aquiredTypeLock; #endif // !FEATURE_CONCURRENT } if ( lockTaken ) { // First try to create generic serializer w/o code generation. var schema = ( providerParameter ?? PolymorphismSchema.Create( typeof( T ), null ) ) as PolymorphismSchema; serializer = GenericSerializer.Create<T>( this, schema ); if ( serializer == null ) { #if !UNITY if ( !this._serializerGeneratorOptions.CanRuntimeCodeGeneration ) { #endif // !UNITY // On debugging, or AOT only envs, use reflection based aproach. serializer = this.GetSerializerWithoutGeneration<T>( schema ) ?? this.OnResolveSerializer<T>( schema ) ?? MessagePackSerializer.CreateReflectionInternal<T>( this, this.EnsureConcreteTypeRegistered( typeof( T ) ), schema ); #if !UNITY } else { // This thread creating new type serializer. serializer = this.OnResolveSerializer<T>( schema ) ?? MessagePackSerializer.CreateInternal<T>( this, schema ); } #endif // !UNITY } } else { // This thread owns existing lock -- thus, constructing self-composite type. return new LazyDelegatingMessagePackSerializer<T>( this, providerParameter ); } // Some types always have to use provider. MessagePackSerializerProvider provider; var asEnumSerializer = serializer as ICustomizableEnumSerializer; if ( asEnumSerializer != null ) { #if DEBUG Contract.Assert( typeof( T ).GetIsEnum(), typeof( T ) + " is not enum but generated serializer is ICustomizableEnumSerializer" ); #endif // DEBUG provider = new EnumMessagePackSerializerProvider( typeof( T ), asEnumSerializer ); } else { #if DEBUG Contract.Assert( !typeof( T ).GetIsEnum(), typeof( T ) + " is enum but generated serializer is not ICustomizableEnumSerializer : " + ( serializer == null ? "null" : serializer.GetType().FullName ) ); #endif // DEBUG // Creates provider even if no schema -- the schema might be specified future for the type. // It is OK to use polymorphic provider for value type. #if !UNITY provider = new PolymorphicSerializerProvider<T>( serializer ); #else provider = new PolymorphicSerializerProvider<T>( this, serializer ); #endif // !UNITY } #if !UNITY Type nullableType; MessagePackSerializerProvider nullableSerializerProvider; SerializerRepository.GetNullableCompanion( typeof( T ), this, serializer, out nullableType, out nullableSerializerProvider ); this._serializers.Register( typeof( T ), provider, nullableType, nullableSerializerProvider, SerializerRegistrationOptions.WithNullable ); #else this._serializers.Register( typeof( T ), provider, null, null, SerializerRegistrationOptions.None ); #endif // !UNITY // Re-get to avoid duplicated registration and handle provider parameter or get the one created by prececing thread. // If T is null and schema is not provided or default schema is provided, then exception will be thrown here from the new provider. return this._serializers.Get<T>( this, providerParameter ); } finally { if ( lockTaken ) { #if !FEATURE_CONCURRENT lock ( this._typeLock ) { this._typeLock.Remove( typeof( T ) ); } #else object dummy; this._typeLock.TryRemove( typeof( T ), out dummy ); #endif // !FEATURE_CONCURRENT } } } }
/// <summary> /// Gets the <see cref="MessagePackSerializer{T}"/> with this instance. /// </summary> /// <typeparam name="T">Type of serialization/deserialization target.</typeparam> /// <param name="providerParameter">A provider specific parameter. See remarks section for details.</param> /// <returns> /// <see cref="MessagePackSerializer{T}"/>. /// If there is exiting one, returns it. /// Else the new instance will be created. /// </returns> /// <remarks> /// <para> /// This method automatically register new instance via <see cref="SerializerRepository.Register{T}(MessagePackSerializer{T})"/>. /// </para> /// <para> /// Currently, only following provider parameters are supported. /// <list type="table"> /// <listheader> /// <term>Target type</term> /// <description>Provider parameter</description> /// </listheader> /// <item> /// <term><see cref="EnumMessagePackSerializer{TEnum}"/> or its descendants.</term> /// <description><see cref="EnumSerializationMethod"/>. The returning instance corresponds to this value for serialization.</description> /// </item> /// </list> /// <note><c>null</c> is valid value for <paramref name="providerParameter"/> and it indeicates default behavior of parameter.</note> /// </para> /// </remarks> public MessagePackSerializer <T> GetSerializer <T>(object providerParameter) { #if !UNITY Contract.Ensures(Contract.Result <MessagePackSerializer <T> >() != null); #endif // !UNITY MessagePackSerializer <T> serializer = null; while (serializer == null) { serializer = this._serializers.Get <T>(this, providerParameter) ?? GenericSerializer.Create <T>(this); if (serializer == null) { #if !XAMIOS && !XAMDROID && !UNITY if (this.IsRuntimeGenerationDisabled) { #endif // !XAMIOS && !XAMDROID && !UNITY serializer = this.GetSerializerWithoutGeneration(typeof(T)) as MessagePackSerializer <T> ?? MessagePackSerializer.CreateReflectionInternal <T>(this); #if !XAMIOS && !XAMDROID && !UNITY } else { object aquiredLock = null; bool lockTaken = false; try { try { } finally { var newLock = new object(); #if SILVERLIGHT || NETFX_35 Monitor.Enter(newLock); try { lock (this._typeLock) { lockTaken = !this._typeLock.TryGetValue(typeof(T), out aquiredLock); if (lockTaken) { aquiredLock = newLock; this._typeLock.Add(typeof(T), newLock); } } #else bool newLockTaken = false; try { Monitor.Enter(newLock, ref newLockTaken); aquiredLock = this._typeLock.GetOrAdd(typeof(T), _ => newLock); lockTaken = newLock == aquiredLock; #endif // if SILVERLIGHT || NETFX_35 } finally { #if SILVERLIGHT || NETFX_35 if (!lockTaken) #else if (!lockTaken && newLockTaken) #endif // if SILVERLIGHT || NETFX_35 { // Release the lock which failed to become 'primary' lock. Monitor.Exit(newLock); } } } if (Monitor.TryEnter(aquiredLock)) { // Decrement monitor counter. Monitor.Exit(aquiredLock); if (lockTaken) { // This thread creating new type serializer. serializer = MessagePackSerializer.CreateInternal <T>(this); } else { // This thread owns existing lock -- thus, constructing self-composite type. // Prevent release owned lock. aquiredLock = null; return(new LazyDelegatingMessagePackSerializer <T>(this, providerParameter)); } } else { // Wait creation by other thread. // Acquire as 'waiting' lock. Monitor.Enter(aquiredLock); } } finally { if (lockTaken) { #if SILVERLIGHT || NETFX_35 lock (this._typeLock) { this._typeLock.Remove(typeof(T)); } #else object dummy; this._typeLock.TryRemove(typeof(T), out dummy); #endif // if SILVERLIGHT || NETFX_35 } if (aquiredLock != null) { // Release primary lock or waiting lock. Monitor.Exit(aquiredLock); } } } #endif // !XAMIOS && !XAMDROID && !UNITY } } if (!this._serializers.Register(serializer) || providerParameter != null) { // Re-get to avoid duplicated registration and handle provider parameter. serializer = this._serializers.Get <T>(this, providerParameter); } return(serializer); }