/// <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 !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
				}
			}
		}
Exemple #3
0
		/// <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);
        }