diff --git a/CHANGES.txt b/CHANGES.txt index 3b6f65795..e1ceee754 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -87,3 +87,35 @@ Release 0.4 - 2013/10/6 * Nullable based unpacker API is deprecated becaue of their poor performance. You should use fast non-nullable APIs instead (properties/methods with 'Data' suffixes). * This version is tested on .NET 4.5 and Mono 2.10.8.1. +Release 0.4.1 - 2013/12/07 + + BUG FIXES + * Fix Readme code error (issue #20.) + * Fix MessagePack.Create() might fail due to type lock synchronization does not coordinate multiple threads (issue #19.) + * Fix deserializing as MessagePackObject fails when unpacking data is list or map (issue #13.) + +Release 0.4.2 - 2014/3/17 + + BUG FIXES + * Add API to re-register serializer (issue #24). It allows you to override default(built-in) serializer as you like. + +Release 0.4.3 - 2014/3/22 + + BUG FIXES + * Fix creating serializer for IEnumerable (and not IList nor IDictionary) causes NullReferenceException. + * Fix built-in object serializer cannot deserialize array/map correctly. + * Fix PackerUnpackerExtensions.Pack() ignore Default serialization context and uses brand-new instance every time. + +Release 0.4.4 - 2014/4/13 + + BUG FIXES + * Fix creating serializer for IDictionary causes NullReferenceException. + * Fix serializers' default constructor IL (it is not used in the library, but can be called via reflection). + +Release 0.4.5 + + BUF FIXES + * Fix creating serializer for abstract dictionary types causes exception in WinRT. + + NEW FEATURES + * System.Runtime.Serialization assembly is not required now (pull-request #29). Thanks @takeshik! diff --git a/MsgPack.nuspec b/MsgPack.nuspec index 243ed3bc4..30ea129fa 100644 --- a/MsgPack.nuspec +++ b/MsgPack.nuspec @@ -3,7 +3,7 @@ MsgPack.Cli MessagePack for CLI - 0.4.0 + 0.4.4 FUJIWARA, Yusuke FUJIWARA, Yusuke http://www.apache.org/licenses/LICENSE-2.0 @@ -12,8 +12,8 @@ false MessagePack is fast, compact, and interoperable binary serialization format. This library provides MessagePack serialization/deserialization APIs. - This release improves performance, adds str8 support, ext type support, improved serializer generator API, new abstract collection support, and some bug fixes. - Copyright 2010-2013 FUJIWARA, Yusuke, all rights reserved. + 0.4 release improves performance, adds str8 support, ext type support, improved serializer generator API, new abstract collection support, and some bug fixes. This release includes bug fixes related to some collection interface types. + Copyright 2010-2014 FUJIWARA, Yusuke, all rights reserved. Serialization MessagePack MsgPack Formatter Binary Serializer diff --git a/README.md b/README.md index 2d3e3f7a5..aca4422de 100644 --- a/README.md +++ b/README.md @@ -7,15 +7,27 @@ This library can be used from ALL CLS compliant languages such as C#, F#, Visual ## Usage +You can serialize/deserialize objects as following: +1. Create serializer via `MessagePackSerializer.Create` generic method. This method creates dependent types serializers as well. +1. Invoke serializer as following: +** `Pack` method with destination `Stream` and target object for serialization. +** `Unpack` method with source `Stream`. + ```c# -var serializer = MessagePackSerializer.Create(); +// Creates serializer. +var serializer = MessagePackSerializer.Create(); +// Pack obj to stream. serializer.Pack(stream, obj); +// Unpack from stream. var unpackedObject = serializer.Unpack(stream); ``` ```vb -Dim serializer = MessagePackSerializer(Of T).Create() +' Creates serializer. +Dim serializer = MessagePackSerializer.Create(Of T)() +' Pack obj to stream. serializer.Pack(stream, obj) +' Unpack from stream. Dim unpackedObject = serializer.Unpack(stream) ``` diff --git a/src/CommonAssemblyInfo.Pack.cs b/src/CommonAssemblyInfo.Pack.cs index c24b2ed35..1be1b0210 100644 --- a/src/CommonAssemblyInfo.Pack.cs +++ b/src/CommonAssemblyInfo.Pack.cs @@ -38,4 +38,4 @@ // Build : Bug fixes and improvements, which does not break API contract, but may break some code depends on internal implementation behaviors. // For example, some programs use reflection to retrieve private fields, analyse human readable exception messages or stack trace, or so. // Revision : Not used. It might be used to indicate target platform. -[assembly: AssemblyInformationalVersion( "0.4.0" )] +[assembly: AssemblyInformationalVersion( "0.4.1" )] diff --git a/src/MsgPack.Mono/MsgPack.Mono.csproj b/src/MsgPack.Mono/MsgPack.Mono.csproj index 74f945211..f12bede47 100644 --- a/src/MsgPack.Mono/MsgPack.Mono.csproj +++ b/src/MsgPack.Mono/MsgPack.Mono.csproj @@ -41,7 +41,6 @@ - diff --git a/src/MsgPack.Mono/Properties/AssemblyInfo.cs b/src/MsgPack.Mono/Properties/AssemblyInfo.cs index 750d6de5a..7206ad79e 100644 --- a/src/MsgPack.Mono/Properties/AssemblyInfo.cs +++ b/src/MsgPack.Mono/Properties/AssemblyInfo.cs @@ -28,7 +28,7 @@ [assembly: AssemblyCopyright( "Copyright © FUJIWARA, Yusuke 2010-2012" )] -[assembly: AssemblyFileVersion( "0.4.1297.568" )] +[assembly: AssemblyFileVersion( "0.4.1435.1085" )] [assembly: SecurityRules( SecurityRuleSet.Level2, SkipVerificationInFullTrust = true )] [assembly: AllowPartiallyTrustedCallers] diff --git a/src/MsgPack.Net35/MsgPack.Net35.csproj b/src/MsgPack.Net35/MsgPack.Net35.csproj index e424ab0b9..d1441d62f 100644 --- a/src/MsgPack.Net35/MsgPack.Net35.csproj +++ b/src/MsgPack.Net35/MsgPack.Net35.csproj @@ -43,7 +43,6 @@ - diff --git a/src/MsgPack.Net35/Properties/AssemblyInfo.cs b/src/MsgPack.Net35/Properties/AssemblyInfo.cs index 6d9115b80..df8b1d65d 100644 --- a/src/MsgPack.Net35/Properties/AssemblyInfo.cs +++ b/src/MsgPack.Net35/Properties/AssemblyInfo.cs @@ -28,7 +28,7 @@ [assembly: AssemblyCopyright( "Copyright © FUJIWARA, Yusuke 2010-2013" )] -[assembly: AssemblyFileVersion( "0.4.1297.568" )] +[assembly: AssemblyFileVersion( "0.4.1435.1085" )] [assembly: AllowPartiallyTrustedCallers] diff --git a/src/MsgPack.Net35/Tuple`n.cs b/src/MsgPack.Net35/Tuple`n.cs index fa48013c9..a775be0e6 100644 --- a/src/MsgPack.Net35/Tuple`n.cs +++ b/src/MsgPack.Net35/Tuple`n.cs @@ -2,7 +2,7 @@ // // MessagePack for CLI // -// Copyright (C) 2010-2012 FUJIWARA, Yusuke +// Copyright (C) 2010-2013 FUJIWARA, Yusuke // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -38,6 +38,11 @@ public static Tuple Create( T1 item1, T2 item2, { return new Tuple( item1, item2, item3, item4 ); } + + public static Tuple Create( T1 item1, T2 item2, T3 item3, T4 item4, T5 item5 ) + { + return new Tuple( item1, item2, item3, item4, item5 ); + } } #if !WINDOWS_PHONE [Serializable] @@ -131,4 +136,70 @@ public override string ToString() return buffer.ToString(); } } +#if !WINDOWS_PHONE + [Serializable] +#endif + internal class Tuple + { + private readonly T1 _item1; + + public T1 Item1 + { + get { return this._item1; } + } + private readonly T2 _item2; + + public T2 Item2 + { + get { return this._item2; } + } + private readonly T3 _item3; + + public T3 Item3 + { + get { return this._item3; } + } + private readonly T4 _item4; + + public T4 Item4 + { + get { return this._item4; } + } + private readonly T5 _item5; + + public T5 Item5 + { + get { return this._item5; } + } + public Tuple( + T1 item1, + T2 item2, + T3 item3, + T4 item4, + T5 item5 + ) + { + this._item1 = item1; + this._item2 = item2; + this._item3 = item3; + this._item4 = item4; + this._item5 = item5; + } + + public override string ToString() + { + var buffer = new StringBuilder(); + buffer.Append( '(' ); + buffer.Append( this._item1 ); + buffer.Append( ", " ); + buffer.Append( this._item2 ); + buffer.Append( ", " ); + buffer.Append( this._item3 ); + buffer.Append( ", " ); + buffer.Append( this._item4 ); + buffer.Append( ", " ); + buffer.Append( this._item5 ); + return buffer.ToString(); + } + } } \ No newline at end of file diff --git a/src/MsgPack.Net35/Tuple`n.tt b/src/MsgPack.Net35/Tuple`n.tt index b36bbbe17..1448aa628 100644 --- a/src/MsgPack.Net35/Tuple`n.tt +++ b/src/MsgPack.Net35/Tuple`n.tt @@ -30,13 +30,13 @@ <# // This file defines Tuple<...> for compatibility. var __typeName = "Tuple"; -var __arities = new []{ 2, 4 }; +var __arities = new []{ 2, 4, 5 }; #> #region -- License Terms -- // // MessagePack for CLI // -// Copyright (C) 2010-2012 FUJIWARA, Yusuke +// Copyright (C) 2010-2013 FUJIWARA, Yusuke // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/src/MsgPack.Serialization.Silverlight.4/MsgPack.Serialization.Silverlight.4.csproj b/src/MsgPack.Serialization.Silverlight.4/MsgPack.Serialization.Silverlight.4.csproj index 1ed2a28be..425d2a3ae 100644 --- a/src/MsgPack.Serialization.Silverlight.4/MsgPack.Serialization.Silverlight.4.csproj +++ b/src/MsgPack.Serialization.Silverlight.4/MsgPack.Serialization.Silverlight.4.csproj @@ -57,7 +57,6 @@ True - diff --git a/src/MsgPack.Serialization.Silverlight.4/Properties/AssemblyInfo.cs b/src/MsgPack.Serialization.Silverlight.4/Properties/AssemblyInfo.cs index 82a9e6f29..9d5d5877d 100644 --- a/src/MsgPack.Serialization.Silverlight.4/Properties/AssemblyInfo.cs +++ b/src/MsgPack.Serialization.Silverlight.4/Properties/AssemblyInfo.cs @@ -27,7 +27,7 @@ [assembly: AssemblyCopyright( "Copyright © FUJIWARA, Yusuke 2010-2012" )] -[assembly: AssemblyFileVersion( "0.4.1297.568" )] +[assembly: AssemblyFileVersion( "0.4.1435.1085" )] #if DEBUG || PERFORMANCE_TEST [assembly: InternalsVisibleTo( "MsgPack.Silverlight.UnitTest, PublicKey=0024000004800000940000000602000000240000525341310004000001000100a967de8de9d45380b93a6aa56f64fc2cb2d3c9d4b400e00de01f31ba9e15cf5ca95926dbf8760cce413eabd711e23df0c133193a570da8a3bb1bdc00ef170fccb2bc033266fa5346442c9cf0b071133d5b484845eab17095652aeafeeb71193506b8294d9c8c91e3fd01cc50bdbc2d0eb78dd655bb8cd0bd3cdbbcb192549cb4" )] diff --git a/src/MsgPack.Serialization.Silverlight.5/MsgPack.Serialization.Silverlight.5.csproj b/src/MsgPack.Serialization.Silverlight.5/MsgPack.Serialization.Silverlight.5.csproj index f24c121de..bd3ef24ff 100644 --- a/src/MsgPack.Serialization.Silverlight.5/MsgPack.Serialization.Silverlight.5.csproj +++ b/src/MsgPack.Serialization.Silverlight.5/MsgPack.Serialization.Silverlight.5.csproj @@ -56,7 +56,6 @@ - diff --git a/src/MsgPack.Serialization.Silverlight.5/Properties/AssemblyInfo.cs b/src/MsgPack.Serialization.Silverlight.5/Properties/AssemblyInfo.cs index 9fd3be3f8..1fbe2d4fd 100644 --- a/src/MsgPack.Serialization.Silverlight.5/Properties/AssemblyInfo.cs +++ b/src/MsgPack.Serialization.Silverlight.5/Properties/AssemblyInfo.cs @@ -27,7 +27,7 @@ [assembly: AssemblyCopyright( "Copyright © FUJIWARA, Yusuke 2010-2012" )] -[assembly: AssemblyFileVersion( "0.4.1297.568" )] +[assembly: AssemblyFileVersion( "0.4.1435.1085" )] #if DEBUG || PERFORMANCE_TEST [assembly: InternalsVisibleTo( "MsgPack.Silverlight.UnitTest, PublicKey=0024000004800000940000000602000000240000525341310004000001000100a967de8de9d45380b93a6aa56f64fc2cb2d3c9d4b400e00de01f31ba9e15cf5ca95926dbf8760cce413eabd711e23df0c133193a570da8a3bb1bdc00ef170fccb2bc033266fa5346442c9cf0b071133d5b484845eab17095652aeafeeb71193506b8294d9c8c91e3fd01cc50bdbc2d0eb78dd655bb8cd0bd3cdbbcb192549cb4" )] diff --git a/src/MsgPack.Serialization.WinRT/Properties/AssemblyInfo.cs b/src/MsgPack.Serialization.WinRT/Properties/AssemblyInfo.cs index 50288901c..8fdf7e0e2 100644 --- a/src/MsgPack.Serialization.WinRT/Properties/AssemblyInfo.cs +++ b/src/MsgPack.Serialization.WinRT/Properties/AssemblyInfo.cs @@ -27,7 +27,7 @@ [assembly: AssemblyCopyright( "Copyright © FUJIWARA, Yusuke 2010-2012" )] -[assembly: AssemblyFileVersion( "0.4.1297.568" )] +[assembly: AssemblyFileVersion( "0.4.1435.1085" )] #if DEBUG || PERFORMANCE_TEST [assembly: InternalsVisibleTo( "MsgPack.UnitTest, PublicKey=0024000004800000940000000602000000240000525341310004000001000100a967de8de9d45380b93a6aa56f64fc2cb2d3c9d4b400e00de01f31ba9e15cf5ca95926dbf8760cce413eabd711e23df0c133193a570da8a3bb1bdc00ef170fccb2bc033266fa5346442c9cf0b071133d5b484845eab17095652aeafeeb71193506b8294d9c8c91e3fd01cc50bdbc2d0eb78dd655bb8cd0bd3cdbbcb192549cb4" )] diff --git a/src/MsgPack.Serialization.WindowsPhone.7.1/MsgPack.Serialization.WindowsPhone.7.1.csproj b/src/MsgPack.Serialization.WindowsPhone.7.1/MsgPack.Serialization.WindowsPhone.7.1.csproj index 96debfad7..3984f298b 100644 --- a/src/MsgPack.Serialization.WindowsPhone.7.1/MsgPack.Serialization.WindowsPhone.7.1.csproj +++ b/src/MsgPack.Serialization.WindowsPhone.7.1/MsgPack.Serialization.WindowsPhone.7.1.csproj @@ -42,7 +42,6 @@ ..\..\bin\sl4-windowsphone71\MsgPack.Serialization.xml - diff --git a/src/MsgPack.Serialization.WindowsPhone.7.1/Properties/AssemblyInfo.cs b/src/MsgPack.Serialization.WindowsPhone.7.1/Properties/AssemblyInfo.cs index ad1bc572b..c3107ff9f 100644 --- a/src/MsgPack.Serialization.WindowsPhone.7.1/Properties/AssemblyInfo.cs +++ b/src/MsgPack.Serialization.WindowsPhone.7.1/Properties/AssemblyInfo.cs @@ -27,7 +27,7 @@ [assembly: AssemblyCopyright( "Copyright © FUJIWARA, Yusuke 2010-2012" )] -[assembly: AssemblyFileVersion( "0.4.1297.568" )] +[assembly: AssemblyFileVersion( "0.4.1435.1085" )] #if DEBUG || PERFORMANCE_TEST [assembly: InternalsVisibleTo( "MsgPack.WindowsPhone.UnitTest" )] diff --git a/src/MsgPack.Silverlight.4/Properties/AssemblyInfo.cs b/src/MsgPack.Silverlight.4/Properties/AssemblyInfo.cs index 32dd2ab82..33044dcac 100644 --- a/src/MsgPack.Silverlight.4/Properties/AssemblyInfo.cs +++ b/src/MsgPack.Silverlight.4/Properties/AssemblyInfo.cs @@ -27,7 +27,7 @@ [assembly: AssemblyCopyright( "Copyright © FUJIWARA, Yusuke 2010-2012" )] -[assembly: AssemblyFileVersion( "0.4.1297.568" )] +[assembly: AssemblyFileVersion( "0.4.1435.1085" )] #if DEBUG || PERFORMANCE_TEST [assembly: InternalsVisibleTo( "MsgPack.Silverlight.UnitTest, PublicKey=0024000004800000940000000602000000240000525341310004000001000100a967de8de9d45380b93a6aa56f64fc2cb2d3c9d4b400e00de01f31ba9e15cf5ca95926dbf8760cce413eabd711e23df0c133193a570da8a3bb1bdc00ef170fccb2bc033266fa5346442c9cf0b071133d5b484845eab17095652aeafeeb71193506b8294d9c8c91e3fd01cc50bdbc2d0eb78dd655bb8cd0bd3cdbbcb192549cb4" )] diff --git a/src/MsgPack.Silverlight.5/Properties/AssemblyInfo.cs b/src/MsgPack.Silverlight.5/Properties/AssemblyInfo.cs index 8e9f03545..d8a0d48a9 100644 --- a/src/MsgPack.Silverlight.5/Properties/AssemblyInfo.cs +++ b/src/MsgPack.Silverlight.5/Properties/AssemblyInfo.cs @@ -27,7 +27,7 @@ [assembly: AssemblyCopyright( "Copyright © FUJIWARA, Yusuke 2010-2012" )] -[assembly: AssemblyFileVersion( "0.4.1297.568" )] +[assembly: AssemblyFileVersion( "0.4.1435.1085" )] #if DEBUG || PERFORMANCE_TEST [assembly: InternalsVisibleTo( "MsgPack.Silverlight.UnitTest, PublicKey=0024000004800000940000000602000000240000525341310004000001000100a967de8de9d45380b93a6aa56f64fc2cb2d3c9d4b400e00de01f31ba9e15cf5ca95926dbf8760cce413eabd711e23df0c133193a570da8a3bb1bdc00ef170fccb2bc033266fa5346442c9cf0b071133d5b484845eab17095652aeafeeb71193506b8294d9c8c91e3fd01cc50bdbc2d0eb78dd655bb8cd0bd3cdbbcb192549cb4" )] diff --git a/src/MsgPack.WinRT/Properties/AssemblyInfo.cs b/src/MsgPack.WinRT/Properties/AssemblyInfo.cs index 663377c63..06c2bbe19 100644 --- a/src/MsgPack.WinRT/Properties/AssemblyInfo.cs +++ b/src/MsgPack.WinRT/Properties/AssemblyInfo.cs @@ -27,7 +27,7 @@ [assembly: AssemblyCopyright( "Copyright © FUJIWARA, Yusuke 2010-2012" )] -[assembly: AssemblyFileVersion( "0.4.1297.568" )] +[assembly: AssemblyFileVersion( "0.4.1435.1085" )] #if DEBUG || PERFORMANCE_TEST [assembly: InternalsVisibleTo( "MsgPack.UnitTest, PublicKey=0024000004800000940000000602000000240000525341310004000001000100a967de8de9d45380b93a6aa56f64fc2cb2d3c9d4b400e00de01f31ba9e15cf5ca95926dbf8760cce413eabd711e23df0c133193a570da8a3bb1bdc00ef170fccb2bc033266fa5346442c9cf0b071133d5b484845eab17095652aeafeeb71193506b8294d9c8c91e3fd01cc50bdbc2d0eb78dd655bb8cd0bd3cdbbcb192549cb4" )] diff --git a/src/MsgPack.WindowsPhone.7.1/Properties/AssemblyInfo.cs b/src/MsgPack.WindowsPhone.7.1/Properties/AssemblyInfo.cs index 710ba04de..1ca074dcb 100644 --- a/src/MsgPack.WindowsPhone.7.1/Properties/AssemblyInfo.cs +++ b/src/MsgPack.WindowsPhone.7.1/Properties/AssemblyInfo.cs @@ -27,7 +27,7 @@ [assembly: AssemblyCopyright( "Copyright © FUJIWARA, Yusuke 2010-2012" )] -[assembly: AssemblyFileVersion( "0.4.1297.568" )] +[assembly: AssemblyFileVersion( "0.4.1435.1085" )] #if DEBUG || PERFORMANCE_TEST [assembly: InternalsVisibleTo( "MsgPack.WindowsPhone.UnitTest" )] diff --git a/src/MsgPack/MsgPack.csproj b/src/MsgPack/MsgPack.csproj index 9ba89fdb8..e28628774 100644 --- a/src/MsgPack/MsgPack.csproj +++ b/src/MsgPack/MsgPack.csproj @@ -91,7 +91,6 @@ - diff --git a/src/MsgPack/PackerUnpackerExtensions.cs b/src/MsgPack/PackerUnpackerExtensions.cs index 9c9c1e82e..e224c3a15 100644 --- a/src/MsgPack/PackerUnpackerExtensions.cs +++ b/src/MsgPack/PackerUnpackerExtensions.cs @@ -130,7 +130,7 @@ public static void PackObject( this Packer source, object value ) Contract.EndContractBlock(); - PackObjectCore( source, value, new SerializationContext() ); + PackObjectCore( source, value, SerializationContext.Default ); } /// diff --git a/src/MsgPack/Properties/AssemblyInfo.cs b/src/MsgPack/Properties/AssemblyInfo.cs index a8bd9e092..a7848633a 100644 --- a/src/MsgPack/Properties/AssemblyInfo.cs +++ b/src/MsgPack/Properties/AssemblyInfo.cs @@ -28,7 +28,7 @@ [assembly: AssemblyCopyright( "Copyright © FUJIWARA, Yusuke 2010-2012" )] -[assembly: AssemblyFileVersion( "0.4.1297.568" )] +[assembly: AssemblyFileVersion( "0.4.1435.1085" )] [assembly: SecurityRules( SecurityRuleSet.Level2, SkipVerificationInFullTrust = true )] [assembly: AllowPartiallyTrustedCallers] diff --git a/src/MsgPack/ReflectionAbstractions.cs b/src/MsgPack/ReflectionAbstractions.cs index 38d74888a..1ac1fcb50 100644 --- a/src/MsgPack/ReflectionAbstractions.cs +++ b/src/MsgPack/ReflectionAbstractions.cs @@ -20,6 +20,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.Contracts; using System.Linq; using System.Reflection; @@ -194,6 +195,26 @@ public static bool IsDefined( this Type source, Type attributeType ) { return source.GetTypeInfo().IsDefined( attributeType ); } + + public static IEnumerable GetCustomAttributesData( this Type source ) + { + return source.GetTypeInfo().CustomAttributes; + } + + public static IEnumerable GetCustomAttributesData( this MemberInfo source ) + { + return source.CustomAttributes; + } + + public static Type GetAttributeType( this CustomAttributeData source ) + { + return source.AttributeType; + } + + public static string GetMemberName( this CustomAttributeNamedArgument source ) + { + return source.MemberName; + } #else public static bool IsDefined( this MemberInfo source, Type attributeType ) { @@ -204,7 +225,100 @@ public static T GetCustomAttribute( this MemberInfo source ) where T : Attribute { return Attribute.GetCustomAttribute( source, typeof( T ) ) as T; - } + } + +#if !SILVERLIGHT + public static Type GetAttributeType( this CustomAttributeData source ) + { + return source.Constructor.DeclaringType; + } + + public static string GetMemberName( this CustomAttributeNamedArgument source ) + { + return source.MemberInfo.Name; + } + +#else + public static Type GetAttributeType( this Attribute source ) + { + return source.GetType(); + } +#endif // !SILVERLIGHT +#endif + +#if NETFX_35 + public static IEnumerable GetCustomAttributesData( this MemberInfo source ) + { + return CustomAttributeData.GetCustomAttributes( source ); + } +#endif // NETFX_35 + +#if SILVERLIGHT + public static IEnumerable GetCustomAttributesData( this MemberInfo source ) + { + return source.GetCustomAttributes( false ).OfType(); + } + + public static IEnumerable GetNamedArguments( this Attribute attribute ) + { + return + attribute.GetType() + .GetMembers( BindingFlags.Public | BindingFlags.Instance ) + .Where( m => m.MemberType == MemberTypes.Field || m.MemberType == MemberTypes.Property ) + .Select( m => new NamedArgument( attribute, m ) ); + } +#else + public static IEnumerable GetNamedArguments( this CustomAttributeData source ) + { + return source.NamedArguments; + } + + public static CustomAttributeTypedArgument GetTypedValue( this CustomAttributeNamedArgument source ) + { + return source.TypedValue; + } +#endif // SILVERLIGHT + +#if SILVERLIGHT + public struct NamedArgument + { + private object _instance; + private MemberInfo _memberInfo; + + public NamedArgument( object instance, MemberInfo memberInfo ) + { + this._instance = instance; + this._memberInfo = memberInfo; + } + + public string GetMemberName() + { + return this._memberInfo.Name; + } + + public KeyValuePair GetTypedValue() + { + Type type; + object value; + PropertyInfo asProperty; + if ( ( asProperty = this._memberInfo as PropertyInfo ) != null ) + { + type = asProperty.PropertyType; + value = asProperty.GetValue( this._instance, null ); + } + else + { + var asField = this._memberInfo as FieldInfo; +#if DEBUG + Contract.Assert( asField != null ); +#endif + type = asField.FieldType; + value = asField.GetValue( this._instance ); + } + + return new KeyValuePair( type, value ); + } + } #endif } } diff --git a/src/MsgPack/Serialization/DataMemberContract.cs b/src/MsgPack/Serialization/DataMemberContract.cs index 90af346d4..2a2f474f9 100644 --- a/src/MsgPack/Serialization/DataMemberContract.cs +++ b/src/MsgPack/Serialization/DataMemberContract.cs @@ -97,25 +97,31 @@ public DataMemberContract( MemberInfo member ) } /// - /// Initializes a new instance of the struct from . + /// Initializes a new instance of the struct. /// /// The target member. - /// The data contract member attribute. This value can be null. - public DataMemberContract( MemberInfo member, DataMemberAttribute attribute ) + /// The name of member. + /// The implication of the nil value for the member. + /// The ID of the member. This value cannot be negative and must be unique in the type. + public DataMemberContract( MemberInfo member, string name, NilImplication nilImplication, int? id ) { Contract.Requires( member != null ); - Contract.Requires( attribute != null ); - this._name = String.IsNullOrEmpty( attribute.Name ) ? member.Name : attribute.Name; - this._nilImplication = Serialization.NilImplication.MemberDefault; - this._id = attribute.Order; + if ( id < 0 ) + { + throw new SerializationException( String.Format( CultureInfo.CurrentCulture, "The member ID cannot be negative. The member is '{0}' in the '{1}' type.", member.Name, member.DeclaringType ) ); + } + + this._name = String.IsNullOrEmpty( name ) ? member.Name : name; + this._nilImplication = nilImplication; + this._id = id ?? UnspecifiedId; } /// /// Initializes a new instance of the struct from . /// /// The target member. - /// The MessagePack member attribute. This value can be null. + /// The MessagePack member attribute. public DataMemberContract( MemberInfo member, MessagePackMemberAttribute attribute ) { Contract.Requires( member != null ); diff --git a/src/MsgPack/Serialization/DefaultSerializers/MsgPack_MessagePackObjectMessagePackSerializer.cs b/src/MsgPack/Serialization/DefaultSerializers/MsgPack_MessagePackObjectMessagePackSerializer.cs index 3fafec0e8..23db0746a 100644 --- a/src/MsgPack/Serialization/DefaultSerializers/MsgPack_MessagePackObjectMessagePackSerializer.cs +++ b/src/MsgPack/Serialization/DefaultSerializers/MsgPack_MessagePackObjectMessagePackSerializer.cs @@ -34,7 +34,14 @@ protected internal sealed override void PackToCore( Packer packer, MessagePackOb protected internal sealed override MessagePackObject UnpackFromCore( Unpacker unpacker ) { - return unpacker.LastReadData; + if ( unpacker.IsArrayHeader || unpacker.IsMapHeader ) + { + return unpacker.UnpackSubtreeData(); + } + else + { + return unpacker.LastReadData; + } } } } diff --git a/src/MsgPack/Serialization/DefaultSerializers/System_ObjectMessagePackSerializer.cs b/src/MsgPack/Serialization/DefaultSerializers/System_ObjectMessagePackSerializer.cs index 5a826756f..10e01111d 100644 --- a/src/MsgPack/Serialization/DefaultSerializers/System_ObjectMessagePackSerializer.cs +++ b/src/MsgPack/Serialization/DefaultSerializers/System_ObjectMessagePackSerializer.cs @@ -34,8 +34,47 @@ protected internal sealed override void PackToCore( Packer packer, object value protected internal sealed override object UnpackFromCore( Unpacker unpacker ) { - var result = unpacker.LastReadData; - return result.IsNil ? null : ( object )result; + if ( unpacker.IsArrayHeader ) + { + var result = new MessagePackObject[ UnpackHelpers.GetItemsCount( unpacker ) ]; + for ( int i = 0; i < result.Length; i++ ) + { + if ( !unpacker.ReadObject( out result[ i ] ) ) + { + throw SerializationExceptions.NewUnexpectedEndOfStream(); + } + } + + return new MessagePackObject( result ); + } + else if ( unpacker.IsMapHeader ) + { + var itemsCount = UnpackHelpers.GetItemsCount( unpacker ); + var result = new MessagePackObjectDictionary( itemsCount ); + for ( int i = 0; i < itemsCount; i++ ) + { + MessagePackObject key; + if ( !unpacker.ReadObject( out key ) ) + { + throw SerializationExceptions.NewUnexpectedEndOfStream(); + } + + MessagePackObject value; + if ( !unpacker.ReadObject( out value ) ) + { + throw SerializationExceptions.NewUnexpectedEndOfStream(); + } + + result.Add( key, value ); + } + + return new MessagePackObject( result ); + } + else + { + var result = unpacker.LastReadData; + return result.IsNil ? MessagePackObject.Nil : result; + } } } } diff --git a/src/MsgPack/Serialization/EmittingSerializers/EmittingSerializerBuilderLogics.cs b/src/MsgPack/Serialization/EmittingSerializers/EmittingSerializerBuilderLogics.cs index 07e440657..fa99675db 100644 --- a/src/MsgPack/Serialization/EmittingSerializers/EmittingSerializerBuilderLogics.cs +++ b/src/MsgPack/Serialization/EmittingSerializers/EmittingSerializerBuilderLogics.cs @@ -191,7 +191,7 @@ private static void CreatePackArrayProceduresCore( Type targetType, SerializerEm private static void CreateUnpackArrayProceduresCore( SerializationContext context, Type targetType, SerializerEmitter emitter, CollectionTraits traits ) { CreateArrayUnpackFrom( context, targetType, emitter, traits ); - CreateArrayUnpackTo( targetType, emitter, traits ); + CreateArrayUnpackTo( context, targetType, emitter, traits ); } private static void CreateArrayUnpackFrom( SerializationContext context, Type targetType, SerializerEmitter emitter, CollectionTraits traits ) @@ -212,6 +212,9 @@ private static void CreateArrayUnpackFrom( SerializationContext context, Type ta il.EmitThrow(); return; } + + // Refresh collection traits. + traits = instanceType.GetCollectionTraits(); } /* @@ -240,7 +243,7 @@ private static void CreateArrayUnpackFrom( SerializationContext context, Type ta il0 => Emittion.EmitGetUnpackerItemsCountAsInt32( il0, 1, localHolder ) ); - EmitInvokeArrayUnpackToHelper( targetType, emitter, traits, il, 1, il0 => il0.EmitAnyLdloc( collection ) ); + EmitInvokeArrayUnpackToHelper( instanceType, emitter, traits, il, 1, il0 => il0.EmitAnyLdloc( collection ) ); il.EmitAnyLdloc( collection ); il.EmitRet(); @@ -251,12 +254,34 @@ private static void CreateArrayUnpackFrom( SerializationContext context, Type ta } } - private static void CreateArrayUnpackTo( Type targetType, SerializerEmitter emitter, CollectionTraits traits ) + private static void CreateArrayUnpackTo( SerializationContext context, Type targetType, SerializerEmitter emitter, CollectionTraits traits ) { var il = emitter.GetUnpackToMethodILGenerator(); try { - EmitInvokeArrayUnpackToHelper( targetType, emitter, traits, il, 1, il0 => il0.EmitAnyLdarg( 2 ) ); + var instanceType = targetType; + + if ( targetType.IsInterface || targetType.IsAbstract ) + { + instanceType = context.DefaultCollectionTypes.GetConcreteType( targetType ); + if ( instanceType == null ) + { + il.EmitTypeOf( targetType ); + il.EmitAnyCall( SerializationExceptions.NewNotSupportedBecauseCannotInstanciateAbstractTypeMethod ); + il.EmitThrow(); + return; + } + } + + if ( traits.AddMethod == null && !targetType.IsArray ) + { + il.EmitTypeOf( targetType ); + il.EmitAnyCall( SerializationExceptions.NewMissingAddMethodMethod ); + il.EmitThrow(); + return; + } + + EmitInvokeArrayUnpackToHelper( instanceType, emitter, traits, il, 1, il0 => il0.EmitAnyLdarg( 2 ) ); il.EmitRet(); } finally @@ -282,6 +307,8 @@ private static void EmitInvokeArrayUnpackToHelper( Type targetType, SerializerEm } else if ( targetType.IsGenericType ) { + Contract.Assert( traits.AddMethod != null, "traits.AddMethod != null" ); + serializerGetting( il, 0 ); loadCollectionEmitting( il ); if ( targetType.IsValueType ) @@ -315,6 +342,8 @@ private static void EmitInvokeArrayUnpackToHelper( Type targetType, SerializerEm } else { + Contract.Assert( traits.AddMethod != null, "traits.AddMethod != null" ); + loadCollectionEmitting( il ); if ( targetType.IsValueType ) { diff --git a/src/MsgPack/Serialization/EmittingSerializers/FieldBasedSerializerEmitter.cs b/src/MsgPack/Serialization/EmittingSerializers/FieldBasedSerializerEmitter.cs index 7d95919ff..7ee585cff 100644 --- a/src/MsgPack/Serialization/EmittingSerializers/FieldBasedSerializerEmitter.cs +++ b/src/MsgPack/Serialization/EmittingSerializers/FieldBasedSerializerEmitter.cs @@ -233,7 +233,7 @@ private ConstructorInfo Create() // : this(null) il.Emit( OpCodes.Ldarg_0 ); il.Emit( OpCodes.Ldnull ); - il.Emit( OpCodes.Call, this._defaultConstructorBuilder ); + il.Emit( OpCodes.Call, this._contextConstructorBuilder ); il.Emit( OpCodes.Ret ); } diff --git a/src/MsgPack/Serialization/ExpressionSerializers/ExpressionSerializerLogics.cs b/src/MsgPack/Serialization/ExpressionSerializers/ExpressionSerializerLogics.cs index cd0dbf7df..69989e755 100644 --- a/src/MsgPack/Serialization/ExpressionSerializers/ExpressionSerializerLogics.cs +++ b/src/MsgPack/Serialization/ExpressionSerializers/ExpressionSerializerLogics.cs @@ -20,6 +20,7 @@ using System; using System.Collections; +using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Linq.Expressions; using System.Reflection; @@ -364,5 +365,169 @@ public static Expression CreateUnpackItem( Expression unpackerParameter, MethodI ) ); } + + internal static Expression> CreateCollectionUnpackToCore( Type type, CollectionTraits traits, ParameterExpression elementSerializerParameter ) + { + var unpackerParameter = Expression.Parameter( typeof( Unpacker ), "unpacker" ); + var instanceParameter = Expression.Parameter( typeof( T ), "instance" ); + + /* + * for ( int i = 0; i < count; i++ ) + * { + * if ( !unpacker.Read() ) + * { + * throw SerializationExceptions.NewMissingItem( i ); + * } + * + * T item; + * if ( !unpacker.IsArrayHeader && !unpacker.IsMapHeader ) + * { + * item = this.ElementSerializer.UnpackFrom( unpacker ); + * } + * else + * { + * using ( Unpacker subtreeUnpacker = unpacker.ReadSubtree() ) + * { + * item = this.ElementSerializer.UnpackFrom( subtreeUnpacker ); + * } + * } + * + * instance[ i ] = item; -- OR -- instance.Add( item ); + * } + */ + + // FIXME: use UnpackHelper + Expression> unpackToCore; + + var safeInstanceParameter = + typeof( T ) == type + ? ( Expression )instanceParameter + : Expression.Convert( instanceParameter, type ); + + if ( type.IsArray ) + { + unpackToCore = + Expression.Lambda>( + Expression.Call( + null, + Metadata._UnpackHelpers.UnpackArrayTo_1.MakeGenericMethod( traits.ElementType ), + unpackerParameter, + Expression.TypeAs( + elementSerializerParameter, + typeof( MessagePackSerializer<> ).MakeGenericType( traits.ElementType ) + ), + safeInstanceParameter + ), + unpackerParameter, + instanceParameter, + elementSerializerParameter + ); + } + else if ( traits.AddMethod == null ) + { + unpackToCore = + Expression.Lambda>( + Expression.Throw( + Expression.Call( + SerializationExceptions.NewMissingAddMethodMethod, + Expression.Call( + // Using RuntimeTypeHandle to avoid WinRT expression tree issue. + Metadata._Type.GetTypeFromHandle, + Expression.Constant( type.TypeHandle ) + ) + ) + ), + unpackerParameter, + instanceParameter, + elementSerializerParameter + ); + } + else if ( type.GetIsGenericType() ) + { + MethodInfo unpackCollectionToMethod; + Type delegateType; + if ( traits.AddMethod.ReturnType == null || traits.AddMethod.ReturnType == typeof( void ) ) + { + unpackCollectionToMethod = Metadata._UnpackHelpers.UnpackCollectionTo_1.MakeGenericMethod( traits.ElementType ); + delegateType = typeof( Action<> ).MakeGenericType( traits.ElementType ); + } + else + { + unpackCollectionToMethod = + Metadata._UnpackHelpers.UnpackCollectionTo_2.MakeGenericMethod( + traits.ElementType, + traits.AddMethod.ReturnType + ); + delegateType = typeof( Func<,> ).MakeGenericType( traits.ElementType, traits.AddMethod.ReturnType ); + } + + var itemParameter = Expression.Parameter( traits.ElementType, "item" ); + unpackToCore = + Expression.Lambda>( + Expression.Call( + null, + unpackCollectionToMethod, + unpackerParameter, + Expression.TypeAs( + elementSerializerParameter, + typeof( MessagePackSerializer<> ).MakeGenericType( traits.ElementType ) + ), + Expression.TypeAs( safeInstanceParameter, typeof( IEnumerable<> ).MakeGenericType( traits.ElementType ) ), + Expression.Lambda( + delegateType, + Expression.Call( + safeInstanceParameter, + traits.AddMethod, + itemParameter + ), + itemParameter + ) + ), + unpackerParameter, + instanceParameter, + elementSerializerParameter + ); + } + else + { + MethodInfo unpackCollectionToMethod; + Type delegateType; + if ( traits.AddMethod.ReturnType == null || traits.AddMethod.ReturnType == typeof( void ) ) + { + unpackCollectionToMethod = Metadata._UnpackHelpers.UnpackNonGenericCollectionTo; + delegateType = typeof( Action<> ).MakeGenericType( traits.ElementType ); + } + else + { + unpackCollectionToMethod = + Metadata._UnpackHelpers.UnpackNonGenericCollectionTo_1.MakeGenericMethod( traits.AddMethod.ReturnType ); + delegateType = typeof( Func<,> ).MakeGenericType( traits.ElementType, traits.AddMethod.ReturnType ); + } + + var itemParameter = Expression.Parameter( traits.ElementType, "item" ); + unpackToCore = + Expression.Lambda>( + Expression.Call( + null, + unpackCollectionToMethod, + unpackerParameter, + Expression.TypeAs( instanceParameter, typeof( IEnumerable ) ), + Expression.Lambda( + delegateType, + Expression.Call( + instanceParameter, + traits.AddMethod, + itemParameter + ), + itemParameter + ) + ), + unpackerParameter, + instanceParameter, + elementSerializerParameter + ); + } + return unpackToCore; + } } } diff --git a/src/MsgPack/Serialization/ExpressionSerializers/ListExpressionMessagePackSerializer`1.cs b/src/MsgPack/Serialization/ExpressionSerializers/ListExpressionMessagePackSerializer`1.cs index 37d0d3f4b..7aae50ba4 100644 --- a/src/MsgPack/Serialization/ExpressionSerializers/ListExpressionMessagePackSerializer`1.cs +++ b/src/MsgPack/Serialization/ExpressionSerializers/ListExpressionMessagePackSerializer`1.cs @@ -31,12 +31,13 @@ internal sealed class ListExpressionMessagePackSerializer : SequenceExpressio { private readonly Func _createInstanceWithCapacity; private readonly Func _createInstance; + private readonly Action _alternativeUnpackTo; public ListExpressionMessagePackSerializer( SerializationContext context, CollectionTraits traits ) : base( context, traits ) { Type type = typeof( T ); - if( type.GetIsAbstract() ) + if ( type.GetIsAbstract() ) { type = context.DefaultCollectionTypes.GetConcreteType( typeof( T ) ) ?? type; } @@ -87,6 +88,16 @@ public ListExpressionMessagePackSerializer( SerializationContext context, Collec } } } + + if ( traits.AddMethod == null ) + { + // Assumes alternative IEnumerable instance is appendable. + var alternativeTraits = type.GetCollectionTraits(); + var elementSerializerParameter = Expression.Parameter( typeof( IMessagePackSerializer ), "elementSerializer" ); + this._alternativeUnpackTo = + ExpressionSerializerLogics.CreateCollectionUnpackToCore( type, alternativeTraits, elementSerializerParameter ) + .Compile(); + } } protected internal override T UnpackFromCore( Unpacker unpacker ) @@ -97,7 +108,14 @@ protected internal override T UnpackFromCore( Unpacker unpacker ) } var instance = this._createInstanceWithCapacity == null ? this._createInstance() : this._createInstanceWithCapacity( UnpackHelpers.GetItemsCount( unpacker ) ); - this.UnpackToCore( unpacker, instance ); + if ( this._alternativeUnpackTo == null ) + { + this.UnpackToCore( unpacker, instance ); + } + else + { + this._alternativeUnpackTo( unpacker, instance, this.ElementSerializer ); + } return instance; } } diff --git a/src/MsgPack/Serialization/ExpressionSerializers/MapExpressionMessagePackSerializer.cs b/src/MsgPack/Serialization/ExpressionSerializers/MapExpressionMessagePackSerializer.cs index 4fd8d24c3..eb76a5c89 100644 --- a/src/MsgPack/Serialization/ExpressionSerializers/MapExpressionMessagePackSerializer.cs +++ b/src/MsgPack/Serialization/ExpressionSerializers/MapExpressionMessagePackSerializer.cs @@ -64,11 +64,17 @@ public MapExpressionMessagePackSerializer( SerializationContext context, Collect this._valueSerializer = traits.ElementType.GetIsGenericType() ? context.GetSerializer( traits.ElementType.GetGenericArguments()[ 1 ] ) : context.GetSerializer( typeof( MessagePackObject ) ); this._getCount = ExpressionSerializerLogics.CreateGetCount( traits ); - var constructor = ExpressionSerializerLogics.GetCollectionConstructor( context, typeof( T ) ); + var targetType = typeof( T ); + if ( targetType.GetIsAbstract() || targetType.GetIsInterface() ) + { + targetType = context.DefaultCollectionTypes.GetConcreteType( targetType ); + } + + var constructor = ExpressionSerializerLogics.GetCollectionConstructor( context, targetType ); if ( constructor == null ) { - this._createInstance = () => { throw SerializationExceptions.NewTargetDoesNotHavePublicDefaultConstructorNorInitialCapacity( typeof( T ) ); }; + this._createInstance = () => { throw SerializationExceptions.NewTargetDoesNotHavePublicDefaultConstructorNorInitialCapacity( targetType ); }; this._createInstanceWithCapacity = null; } else if ( constructor.GetParameters().Length == 1 ) diff --git a/src/MsgPack/Serialization/ExpressionSerializers/SequenceExpressionMessagePackSerializer`1.cs b/src/MsgPack/Serialization/ExpressionSerializers/SequenceExpressionMessagePackSerializer`1.cs index 3fdef9588..2710db7cb 100644 --- a/src/MsgPack/Serialization/ExpressionSerializers/SequenceExpressionMessagePackSerializer`1.cs +++ b/src/MsgPack/Serialization/ExpressionSerializers/SequenceExpressionMessagePackSerializer`1.cs @@ -52,6 +52,11 @@ protected CollectionTraits Traits private readonly IMessagePackSerializer _elementSerializer; + internal IMessagePackSerializer ElementSerializer + { + get { return this._elementSerializer; } + } + private readonly Action _packToCore; private readonly Action _unpackToCore; #if !SILVERLIGHT @@ -79,37 +84,60 @@ protected SequenceExpressionMessagePackSerializer( SerializationContext context, * elementSerializer.PackTo( packer, item ); * } */ - var packToCore = - Expression.Lambda>( - Expression.Block( + var packToCoreBody = new List( 3 ); + var variables = new List( 0 ); + var targetCollection = objectTreeParameter; + if ( traits.AddMethod == null && !typeof( T ).IsArray ) + { + targetCollection = Expression.Variable( traits.ElementType.MakeArrayType(), "asArray" ); + variables.Add( targetCollection ); + packToCoreBody.Add( + Expression.Assign( + targetCollection, + Expression.Call( + Metadata._Enumerable.ToArray1Method.MakeGenericMethod( traits.ElementType ), + objectTreeParameter + ) + ) + ); + } + + packToCoreBody.Add( + Expression.Call( + packerParameter, + Metadata._Packer.PackArrayHeader, + ExpressionSerializerLogics.CreateGetCountExpression( traits, objectTreeParameter ) + ) + ); + + packToCoreBody.Add( + traits.AddMethod == null + ? ExpressionSerializerLogics.For( + Expression.ArrayLength( targetCollection ), + indexVariable => Expression.Call( + Expression.TypeAs( elementSerializerParameter, elementSerializerType ), + typeof( MessagePackSerializer<> ).MakeGenericType( traits.ElementType ).GetMethod( "PackTo" ), packerParameter, - Metadata._Packer.PackArrayHeader, - ExpressionSerializerLogics.CreateGetCountExpression( traits, objectTreeParameter ) - ), - traits.AddMethod == null - ? ExpressionSerializerLogics.For( - Expression.ArrayLength( objectTreeParameter ), - indexVariable => - Expression.Call( - Expression.TypeAs( elementSerializerParameter, elementSerializerType ), - typeof( MessagePackSerializer<> ).MakeGenericType( traits.ElementType ).GetMethod( "PackTo" ), - packerParameter, - Expression.ArrayIndex( objectTreeParameter, indexVariable ) - ) + Expression.ArrayIndex( targetCollection, indexVariable ) ) - : ExpressionSerializerLogics.ForEach( - objectTreeParameter, - traits, - elementVariable => - Expression.Call( - Expression.TypeAs( elementSerializerParameter, elementSerializerType ), - typeof( MessagePackSerializer<> ).MakeGenericType( traits.ElementType ).GetMethod( "PackTo" ), - packerParameter, - elementVariable - ) + ) + : ExpressionSerializerLogics.ForEach( + targetCollection, + traits, + elementVariable => + Expression.Call( + Expression.TypeAs( elementSerializerParameter, elementSerializerType ), + typeof( MessagePackSerializer<> ).MakeGenericType( traits.ElementType ).GetMethod( "PackTo" ), + packerParameter, + elementVariable ) - ), + ) + ); + + var packToCore = + Expression.Lambda>( + Expression.Block( variables, packToCoreBody ), packerParameter, objectTreeParameter, elementSerializerParameter ); @@ -122,125 +150,7 @@ protected SequenceExpressionMessagePackSerializer( SerializationContext context, this._packToCore = packToCore.Compile(); - var unpackerParameter = Expression.Parameter( typeof( Unpacker ), "unpacker" ); - var instanceParameter = Expression.Parameter( typeof( T ), "instance" ); - var countParamter = Expression.Parameter( typeof( int ), "count" ); - - /* - * for ( int i = 0; i < count; i++ ) - * { - * if ( !unpacker.Read() ) - * { - * throw SerializationExceptions.NewMissingItem( i ); - * } - * - * T item; - * if ( !unpacker.IsArrayHeader && !unpacker.IsMapHeader ) - * { - * item = this.ElementSerializer.UnpackFrom( unpacker ); - * } - * else - * { - * using ( Unpacker subtreeUnpacker = unpacker.ReadSubtree() ) - * { - * item = this.ElementSerializer.UnpackFrom( subtreeUnpacker ); - * } - * } - * - * instance[ i ] = item; -- OR -- instance.Add( item ); - * } - */ - - // FIXME: use UnpackHelper - Expression> unpackToCore; - - if ( typeof( T ).IsArray ) - { - unpackToCore = - Expression.Lambda>( - Expression.Call( - null, - _UnpackHelpers.UnpackArrayTo_1.MakeGenericMethod( traits.ElementType ), - unpackerParameter, - Expression.TypeAs( elementSerializerParameter, typeof( MessagePackSerializer<> ).MakeGenericType( traits.ElementType ) ), - instanceParameter - ), - unpackerParameter, instanceParameter, elementSerializerParameter - ); - } - else if ( typeof( T ).GetIsGenericType() ) - { - MethodInfo unpackCollectionToMethod; - Type delegateType; - if ( traits.AddMethod.ReturnType == null || traits.AddMethod.ReturnType == typeof( void ) ) - { - unpackCollectionToMethod = _UnpackHelpers.UnpackCollectionTo_1.MakeGenericMethod( traits.ElementType ); - delegateType = typeof( Action<> ).MakeGenericType( traits.ElementType ); - } - else - { - unpackCollectionToMethod = _UnpackHelpers.UnpackCollectionTo_2.MakeGenericMethod( traits.ElementType, traits.AddMethod.ReturnType ); - delegateType = typeof( Func<,> ).MakeGenericType( traits.ElementType, traits.AddMethod.ReturnType ); - } - - var itemParameter = Expression.Parameter( traits.ElementType, "item" ); - unpackToCore = - Expression.Lambda>( - Expression.Call( - null, - unpackCollectionToMethod, - unpackerParameter, - Expression.TypeAs( elementSerializerParameter, typeof( MessagePackSerializer<> ).MakeGenericType( traits.ElementType ) ), - Expression.TypeAs( instanceParameter, typeof( IEnumerable<> ).MakeGenericType( traits.ElementType ) ), - Expression.Lambda( - delegateType, - Expression.Call( - instanceParameter, - traits.AddMethod, - itemParameter - ), - itemParameter - ) - ), - unpackerParameter, instanceParameter, elementSerializerParameter - ); - } - else - { - MethodInfo unpackCollectionToMethod; - Type delegateType; - if ( traits.AddMethod.ReturnType == null || traits.AddMethod.ReturnType == typeof( void ) ) - { - unpackCollectionToMethod = _UnpackHelpers.UnpackNonGenericCollectionTo; - delegateType = typeof( Action<> ).MakeGenericType( traits.ElementType ); - } - else - { - unpackCollectionToMethod = _UnpackHelpers.UnpackNonGenericCollectionTo_1.MakeGenericMethod( traits.AddMethod.ReturnType ); - delegateType = typeof( Func<,> ).MakeGenericType( traits.ElementType, traits.AddMethod.ReturnType ); - } - - var itemParameter = Expression.Parameter( traits.ElementType, "item" ); - unpackToCore = - Expression.Lambda>( - Expression.Call( - null, - unpackCollectionToMethod, - unpackerParameter, - Expression.TypeAs( instanceParameter, typeof( IEnumerable ) ), - Expression.Lambda( - delegateType, - Expression.Call( - instanceParameter, - traits.AddMethod, - itemParameter - ), - itemParameter - ) - ), - unpackerParameter, instanceParameter, elementSerializerParameter - ); - } + var unpackToCore = ExpressionSerializerLogics.CreateCollectionUnpackToCore( typeof(T), traits, elementSerializerParameter ); #if !SILVERLIGHT if ( context.GeneratorOption == SerializationMethodGeneratorOption.CanDump ) diff --git a/src/MsgPack/Serialization/ReflectionExtensions.cs b/src/MsgPack/Serialization/ReflectionExtensions.cs index 0ca6c6ccf..52c9bfbb6 100644 --- a/src/MsgPack/Serialization/ReflectionExtensions.cs +++ b/src/MsgPack/Serialization/ReflectionExtensions.cs @@ -121,7 +121,10 @@ public static CollectionTraits GetCollectionTraits( this Type source ) // Block to limit variable scope { - var ienumetaorT = getEnumerator.ReturnType.GetInterfaces().FirstOrDefault( @interface => @interface.GetIsGenericType() && @interface.GetGenericTypeDefinition() == typeof( IEnumerator<> ) ); + var ienumetaorT = + IsIEnumeratorT(getEnumerator.ReturnType) + ? getEnumerator.ReturnType + : getEnumerator.ReturnType.GetInterfaces().FirstOrDefault( IsIEnumeratorT ); if ( ienumetaorT != null ) { var elementType = ienumetaorT.GetGenericArguments()[ 0 ]; @@ -130,7 +133,7 @@ public static CollectionTraits GetCollectionTraits( this Type source ) CollectionKind.Array, GetAddMethod( source, elementType ), getEnumerator, - null, + GetCollectionTCountProperty( source, elementType ), elementType ); } @@ -141,7 +144,22 @@ public static CollectionTraits GetCollectionTraits( this Type source ) Type idictionaryT = null; Type ienumerable = null; Type idictionary = null; - foreach ( var type in source.FindInterfaces( FilterCollectionType, null ) ) + + var sourceInterfaces = source.FindInterfaces( FilterCollectionType, null ); + if ( source.GetIsInterface() && FilterCollectionType( source, null ) ) + { + var originalSourceInterfaces = sourceInterfaces.ToArray(); + var concatenatedSourceInterface = new Type[ originalSourceInterfaces.Length + 1 ]; + concatenatedSourceInterface[ 0 ] = source; + for ( int i = 0; i < originalSourceInterfaces.Length; i++ ) + { + concatenatedSourceInterface[ i + 1 ] = originalSourceInterfaces[ i ]; + } + + sourceInterfaces = concatenatedSourceInterface; + } + + foreach ( var type in sourceInterfaces ) { if ( type == typeof( IDictionary ) ) { @@ -370,6 +388,10 @@ private static bool FilterCollectionType( Type type, object filterCriteria ) #endif } + private static bool IsIEnumeratorT( Type @interface ) + { + return @interface.GetIsGenericType() && @interface.GetGenericTypeDefinition() == typeof( IEnumerator<> ); + } #if WINDOWS_PHONE public static IEnumerable FindInterfaces( this Type source, Func filter, object criterion ) { diff --git a/src/MsgPack/Serialization/SerializationContext.cs b/src/MsgPack/Serialization/SerializationContext.cs index ccd359b93..d2a46c3ca 100644 --- a/src/MsgPack/Serialization/SerializationContext.cs +++ b/src/MsgPack/Serialization/SerializationContext.cs @@ -64,7 +64,7 @@ public static SerializationContext Default private readonly SerializerRepository _serializers; #if SILVERLIGHT || NETFX_35 - private readonly HashSet _typeLock; + private readonly Dictionary _typeLock; #else private readonly ConcurrentDictionary _typeLock; #endif @@ -140,8 +140,8 @@ public SerializationMethod SerializationMethod { switch ( value ) { - case Serialization.SerializationMethod.Array: - case Serialization.SerializationMethod.Map: + case SerializationMethod.Array: + case SerializationMethod.Map: { break; } @@ -229,14 +229,14 @@ internal SerializationContext( Contract.Requires( serializers != null ); this._compatibilityOptions = - new SerializationCompatibilityOptions() + new SerializationCompatibilityOptions { PackerCompatibilityOptions = packerCompatibilityOptions }; this._serializers = serializers; #if SILVERLIGHT || NETFX_35 - this._typeLock = new HashSet(); + this._typeLock = new Dictionary(); #else this._typeLock = new ConcurrentDictionary(); #endif @@ -258,58 +258,115 @@ internal bool ContainsSerializer( Type rootType ) /// Else the new instance will be created. /// /// - /// This method automatically register new instance via . + /// This method automatically register new instance via . /// public MessagePackSerializer GetSerializer() { Contract.Ensures( Contract.Result>() != null ); - var serializer = this._serializers.Get( this ); - if ( serializer == null ) + MessagePackSerializer serializer = null; + while ( serializer == null ) { - bool lockTaken = false; - try + serializer = this._serializers.Get( this ); + if ( serializer == null ) { - try { } - finally + object aquiredLock = null; + bool lockTaken = false; + try { -#if SILVERLIGHT || NETFX_35 - lock( this._typeLock ) + try { } + finally { - lockTaken = this._typeLock.Add( typeof( T ) ); - } + 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 - lockTaken = this._typeLock.TryAdd( typeof( T ), null ); + bool newLockTaken = false; + try + { + Monitor.Enter( newLock, ref newLockTaken ); + aquiredLock = this._typeLock.GetOrAdd( typeof( T ), _ => newLock ); + lockTaken = newLock == aquiredLock; #endif - } + } + finally + { +#if SILVERLIGHT || NETFX_35 + if ( !lockTaken ) +#else + if ( !lockTaken && newLockTaken ) +#endif + { + // Release the lock which failed to become 'primary' lock. + Monitor.Exit( newLock ); + } + } + } - if ( !lockTaken ) - { - return new LazyDelegatingMessagePackSerializer( this ); + if ( Monitor.TryEnter( aquiredLock ) ) + { + // Decrement monitor counter. + Monitor.Exit( aquiredLock ); + + if ( lockTaken ) + { + // This thread creating new type serializer. + serializer = MessagePackSerializer.Create( this ); + } + else + { + // This thread owns existing lock -- thus, constructing self-composite type. + + // Prevent release owned lock. + aquiredLock = null; + return new LazyDelegatingMessagePackSerializer( this ); + } + } + else + { + // Wait creation by other thread. + // Acquire as 'waiting' lock. + Monitor.Enter( aquiredLock ); + } } - - serializer = MessagePackSerializer.Create( this ); - } - finally - { - if ( lockTaken ) + finally { -#if SILVERLIGHT || NETFX_35 - lock( this._typeLock ) + if ( lockTaken ) { - this._typeLock.Remove( typeof( T ) ); - } +#if SILVERLIGHT || NETFX_35 + lock( this._typeLock ) + { + this._typeLock.Remove( typeof( T ) ); + } #else - object dummy; - this._typeLock.TryRemove( typeof( T ), out dummy ); + object dummy; + this._typeLock.TryRemove( typeof( T ), out dummy ); #endif + } + + if ( aquiredLock != null ) + { + // Release primary lock or waiting lock. + Monitor.Exit( aquiredLock ); + } } } + } - if ( !this._serializers.Register( serializer ) ) - { - serializer = this._serializers.Get( this ); - } + if ( !this._serializers.Register( serializer ) ) + { + serializer = this._serializers.Get( this ); } return serializer; @@ -374,6 +431,9 @@ public IMessagePackSingleObjectSerializer Get( SerializationContext context, Typ ), contextParameter ).Compile(); +#endif +#if DEBUG + Contract.Assert( func != null ); #endif this._cache[ targetType.TypeHandle ] = func; } @@ -408,10 +468,13 @@ private static Func> CreateFunc() } #endif +// ReSharper disable UnusedMember.Local + // This method is invoked via Reflection on SerializerGetter.Get(). public static IMessagePackSingleObjectSerializer Get( SerializationContext context ) { return _func( context ); } + // ReSharper restore UnusedMember.Local } } } diff --git a/src/MsgPack/Serialization/SerializationExceptions.cs b/src/MsgPack/Serialization/SerializationExceptions.cs index 03d402c9a..474b2c087 100644 --- a/src/MsgPack/Serialization/SerializationExceptions.cs +++ b/src/MsgPack/Serialization/SerializationExceptions.cs @@ -226,13 +226,18 @@ public static Exception NewUnexpectedEndOfStream() return new SerializationException( "Stream unexpectedly ends." ); } + /// + /// of method. + /// + internal static readonly MethodInfo NewMissingAddMethodMethod = FromExpression.ToMethod( ( Type type ) => NewMissingAddMethod( type ) ); + /// /// This is intended to MsgPack for CLI internal use. Do not use this type from application directly. /// Returns new exception to notify that target collection type does not declare appropriate Add(T) method. /// /// The target type. /// instance. It will not be null. - internal static Exception NewMissingAddMethod( Type type ) + public static Exception NewMissingAddMethod( Type type ) { Contract.Requires( type != null ); Contract.Ensures( Contract.Result() != null ); diff --git a/src/MsgPack/Serialization/SerializerBuilder`1.cs b/src/MsgPack/Serialization/SerializerBuilder`1.cs index 2634d2df5..328ea8a19 100644 --- a/src/MsgPack/Serialization/SerializerBuilder`1.cs +++ b/src/MsgPack/Serialization/SerializerBuilder`1.cs @@ -32,7 +32,7 @@ namespace MsgPack.Serialization /// Build serializer for . /// /// Object to be serialized/deserialized. - [ContractClass(typeof(SerializerBuilderContract<>))] + [ContractClass( typeof( SerializerBuilderContract<> ) )] internal abstract class SerializerBuilder { private readonly SerializationContext _context; @@ -95,8 +95,8 @@ public MessagePackSerializer CreateSerializer() if ( this.Context.CompatibilityOptions.OneBoundDataMemberOrder && entries[ 0 ].Contract.Id == 0 ) { throw new NotSupportedException( "Cannot specify order value 0 on DataMemberAttribute when SerializationContext.CompatibilityOptions.OneBoundDataMemberOrder is set to true." ); - } - + } + var maxId = entries.Max( item => item.Contract.Id ); var result = new List( maxId + 1 ); for ( int source = 0, destination = this.Context.CompatibilityOptions.OneBoundDataMemberOrder ? 1 : 0; source < entries.Length; source++, destination++ ) @@ -149,15 +149,38 @@ private static IEnumerable GetTargetMembers() ); } - if ( typeof( TObject ).IsDefined( typeof( DataContractAttribute ) ) ) + if ( typeof( TObject ).GetCustomAttributesData().Any( attr => + attr.GetAttributeType().FullName == "System.Runtime.Serialization.DataContractAttribute" ) ) { return - members.Where( item => item.IsDefined( typeof( DataMemberAttribute ) ) ) - .Select( member => - new SerializingMember( - member, - new DataMemberContract( member, member.GetCustomAttribute() ) - ) + members.Select( + item => + new + { + member = item, + data = item.GetCustomAttributesData() + .FirstOrDefault( + data => data.GetAttributeType().FullName == "System.Runtime.Serialization.DataMemberAttribute" ) + } + ).Where( item => item.data != null ) + .Select( + item => + { + var name = item.data.GetNamedArguments() + .Where( arg => arg.GetMemberName() == "Name" ) + .Select( arg => ( string )arg.GetTypedValue().Value ) + .FirstOrDefault(); + var id = item.data.GetNamedArguments() + .Where( arg => arg.GetMemberName() == "Order" ) + .Select( arg => ( int? )arg.GetTypedValue().Value ) + .FirstOrDefault(); + + return + new SerializingMember( + item.member, + new DataMemberContract( item.member, name, NilImplication.MemberDefault, id ) + ); + } ); } @@ -208,7 +231,7 @@ private static IEnumerable GetTargetMembers() public abstract MessagePackSerializer CreateTupleSerializer(); } - [ContractClassFor(typeof(SerializerBuilder<>))] + [ContractClassFor( typeof( SerializerBuilder<> ) )] internal abstract class SerializerBuilderContract : SerializerBuilder { protected SerializerBuilderContract() : base( null ) { } diff --git a/src/MsgPack/Serialization/SerializerRepository.cs b/src/MsgPack/Serialization/SerializerRepository.cs index ba4ccbc52..22a887b4f 100644 --- a/src/MsgPack/Serialization/SerializerRepository.cs +++ b/src/MsgPack/Serialization/SerializerRepository.cs @@ -119,6 +119,24 @@ public bool Register( MessagePackSerializer serializer ) return this._repository.Register( typeof( T ), serializer, allowOverwrite: false ); } + /// + /// Registers a forcibley. + /// + /// The type of serialization target. + /// instance. + /// + /// is null. + /// + public void RegisterOverride( MessagePackSerializer serializer ) + { + if ( serializer == null ) + { + throw new ArgumentNullException( "serializer" ); + } + + this._repository.Register( typeof( T ), serializer, allowOverwrite: true ); + } + private static readonly Dictionary _defaults = new Dictionary( 4 ) { diff --git a/test/MsgPack.UnitTest/PackerTest.Pack.Miscs.cs b/test/MsgPack.UnitTest/PackerTest.Pack.Miscs.cs index 1512f71b8..a40c6d232 100644 --- a/test/MsgPack.UnitTest/PackerTest.Pack.Miscs.cs +++ b/test/MsgPack.UnitTest/PackerTest.Pack.Miscs.cs @@ -24,6 +24,8 @@ using System.IO; using System.Linq; using System.Text; + +using MsgPack.Serialization; #if !MSTEST using NUnit.Framework; #else @@ -265,12 +267,16 @@ public void TestPackItems_NotNull__AsArray() } [Test] - public void TestPackItems_NotNullEnumerable_Fail() + public void TestPackItems_NotNullEnumerable_AsArray() { using ( var buffer = new MemoryStream() ) using ( var packer = Packer.Create( buffer ) ) { - Assert.Throws( () => packer.Pack( Enumerable.Range( 1, 3 ) ) ); + packer.Pack( Enumerable.Range( 1, 3 ) ); + Assert.AreEqual( + new byte[] { 0x93, 1, 2, 3 }, + buffer.ToArray() + ); } } diff --git a/test/MsgPack.UnitTest/Serialization/AutoMessagePackSerializerTest.cs b/test/MsgPack.UnitTest/Serialization/AutoMessagePackSerializerTest.cs index 739ee8680..2caed7134 100644 --- a/test/MsgPack.UnitTest/Serialization/AutoMessagePackSerializerTest.cs +++ b/test/MsgPack.UnitTest/Serialization/AutoMessagePackSerializerTest.cs @@ -1072,6 +1072,58 @@ private static void AssertArraySegmentEquals( object x, object y ) #endif } + [Test] + public void TestIssue25_Plain() + { + var hasEnumerable = new HasEnumerable { Numbers = new[] { 1, 2 } }; + var target = MessagePackSerializer.Create( this.GetSerializationContext() ); + using ( var buffer = new MemoryStream() ) + { + target.Pack( buffer, hasEnumerable ); + buffer.Position = 0; + var result = target.Unpack( buffer ); + var resultNumbers = result.Numbers.ToArray(); + Assert.That( resultNumbers.Length, Is.EqualTo( 2 ) ); + Assert.That( resultNumbers[ 0 ], Is.EqualTo( 1 ) ); + Assert.That( resultNumbers[ 1 ], Is.EqualTo( 2 ) ); + } + } + + public class HasEnumerable + { + public IEnumerable Numbers { get; set; } + } + + [Test] + public void TestIssue25_SelfComposite() + { + SerializationContext serializationContext = + SerializationContext.Default; + try + { + + serializationContext.Serializers.Register( new PersonSerializer() ); + serializationContext.Serializers.Register( new ChildrenSerializer() ); + + object[] array = new object[] { new Person { Name = "Joe" }, 3 }; + + MessagePackSerializer context = + serializationContext.GetSerializer(); + + byte[] packed = context.PackSingleObject( array ); + object[] unpacked = context.UnpackSingleObject( packed ); + + Assert.That( unpacked.Length, Is.EqualTo( 2 ) ); + Assert.That( ( ( MessagePackObject )unpacked[ 0 ] ).AsDictionary()[ "Name" ].AsString(), Is.EqualTo( "Joe" ) ); + Assert.That( ( ( MessagePackObject )unpacked[ 0 ] ).AsDictionary()[ "Children" ].IsNil ); + Assert.That( ( MessagePackObject )unpacked[ 1 ], Is.EqualTo( new MessagePackObject( 3 ) ) ); + } + finally + { + SerializationContext.Default = new SerializationContext(); + } + } + public struct TestValueType { public string StringField; @@ -1290,7 +1342,7 @@ public ICollection Values public void Add( KeyValuePair item ) { - throw new NotImplementedException(); + this.Add( item.Key, item.Value ); } public void Clear() @@ -1410,5 +1462,123 @@ public class WithAbstractNonCollection { public Stream NonCollection { get; set; } } + // Issue #25 + + public class Person : IEnumerable + { + public string Name { get; set; } + + internal IEnumerable Children { get; set; } + + public IEnumerator GetEnumerator() + { + return Children.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } + + public class PersonSerializer : MessagePackSerializer + { + protected internal override void PackToCore( Packer packer, Person objectTree ) + { + packer.PackMapHeader( 2 ); + packer.Pack( "Name" ); + packer.Pack( objectTree.Name ); + packer.Pack( "Children" ); + if ( objectTree.Children == null ) + { + packer.PackNull(); + } + else + { + this.PackPeople( packer, objectTree.Children ); + } + } + + internal void PackPeople( Packer packer, IEnumerable people ) + { + var children = people.ToArray(); + + packer.PackArrayHeader( children.Length ); + foreach ( var child in children ) + { + this.PackTo( packer, child ); + } + } + + protected internal override Person UnpackFromCore( Unpacker unpacker ) + { + Assert.That( unpacker.IsMapHeader ); + Assert.That( unpacker.ItemsCount, Is.EqualTo( 2 ) ); + var person = new Person(); + for ( int i = 0; i < 2; i++ ) + { + string key; + Assert.That( unpacker.ReadString( out key ) ); + switch ( key ) + { + case "Name": + { + + string name; + Assert.That( unpacker.ReadString( out name ) ); + person.Name = name; + break; + } + case "Children": + { + Assert.That( unpacker.Read() ); + if ( !unpacker.LastReadData.IsNil ) + { + person.Children = this.UnpackPeople( unpacker ); + } + break; + } + } + } + + return person; + } + + internal IEnumerable UnpackPeople( Unpacker unpacker ) + { + Assert.That( unpacker.IsArrayHeader ); + var itemsCount = ( int )unpacker.ItemsCount; + var people = new List( itemsCount ); + for ( int i = 0; i < itemsCount; i++ ) + { + people.Add( this.UnpackFrom( unpacker ) ); + } + + return people; + } + } + + public class ChildrenSerializer : MessagePackSerializer> + { + private readonly PersonSerializer _personSerializer = new PersonSerializer(); + + protected internal override void PackToCore( Packer packer, IEnumerable objectTree ) + { + if ( objectTree is Person ) + { + this._personSerializer.PackTo( packer, objectTree as Person ); + } + else + { + this._personSerializer.PackPeople( packer, objectTree ); + } + } + + protected internal override IEnumerable UnpackFromCore( Unpacker unpacker ) + { + return this._personSerializer.UnpackPeople( unpacker ); + } + } + } } \ No newline at end of file diff --git a/test/MsgPack.UnitTest/Serialization/MessagePackSerializerTTest.cs b/test/MsgPack.UnitTest/Serialization/MessagePackSerializerTTest.cs index 41c0e3b50..01834ef7a 100644 --- a/test/MsgPack.UnitTest/Serialization/MessagePackSerializerTTest.cs +++ b/test/MsgPack.UnitTest/Serialization/MessagePackSerializerTTest.cs @@ -19,9 +19,11 @@ #endregion -- License Terms -- using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.Serialization; +using MsgPack.Serialization.DefaultSerializers; #if !NETFX_CORE using MsgPack.Serialization.EmittingSerializers; #else @@ -486,6 +488,60 @@ public void TestIssue10_Empty_Reader() } + [Test] + public void TestIssue13_StringListMapAsMpoDictionary() + { + var target = MessagePackSerializer.Create>(); + using ( var buffer = new MemoryStream( Convert.FromBase64String( "gadyZXN1bHRzkss/8AAAAAAAAMtAAAAAAAAAAA==" ) ) ) + { + var result = target.Unpack( buffer ); + Assert.That( result.Count, Is.EqualTo( 1 ) ); + Assert.That( result.First().Key == "results", "{0}.Key != results", result.First().Key ); + Assert.That( result.First().Value.IsList, "{0}.Value is not list", result.First().Value.UnderlyingType ); + } + } + + [Test] + public void TestIssue13_ListAsMpo() + { + var target = new MsgPack_MessagePackObjectMessagePackSerializer( PackerCompatibilityOptions.Classic ); + using ( var buffer = new MemoryStream( new byte[] { 0x91, 2 } ) ) + { + var result = target.Unpack( buffer ); + Assert.That( result.IsList, "{0} is not list", result.UnderlyingType ); + Assert.That( result.AsList().Count, Is.EqualTo( 1 ) ); + Assert.That( result.AsList().First() == 2, "{0}[0] != 2", result ); + } + } + + [Test] + public void TestIssue13_MapAsMpo() + { + var target = new MsgPack_MessagePackObjectMessagePackSerializer( PackerCompatibilityOptions.Classic ); + using ( var buffer = new MemoryStream( new byte[] { 0x81, 2, 3 } ) ) + { + var result = target.Unpack( buffer ); + Assert.That( result.IsDictionary, "{0} is not dictionary", result.UnderlyingType ); + Assert.That( result.AsDictionary().Count, Is.EqualTo( 1 ) ); + Assert.That( result.AsDictionary().First().Key == 2, "{0}.First().Key != 2", result ); + Assert.That( result.AsDictionary().First().Value == 3, "{0}.First().Value != 3", result ); + } + } + + [Test] + public void TestIssue28() + { + var target = CreateTarget(); + using ( var buffer = new MemoryStream() ) + { + var value = new WithReadOnlyProperty { Number = 123 }; + target.Pack( buffer, value ); + buffer.Position = 0; + var result = target.Unpack( buffer ); + Assert.That( value.Number, Is.EqualTo( result.Number ) ); + } + } + private void TestIssue10_Reader( Inner inner ) { var serializer = MessagePackSerializer.Create(); @@ -534,4 +590,10 @@ public class Inner public string C = "C"; } } + + public class WithReadOnlyProperty + { + public int Number { get; set; } + public string AsString{get { return this.Number.ToString(); }} + } } diff --git a/test/MsgPack.UnitTest/Serialization/SerializationContextTest.cs b/test/MsgPack.UnitTest/Serialization/SerializationContextTest.cs index aba2ed64d..6739ff966 100644 --- a/test/MsgPack.UnitTest/Serialization/SerializationContextTest.cs +++ b/test/MsgPack.UnitTest/Serialization/SerializationContextTest.cs @@ -23,8 +23,12 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; +using System.Linq; using System.Threading; using System.Threading.Tasks; + +using MsgPack.Serialization.DefaultSerializers; +using MsgPack.Serialization.EmittingSerializers; #if !MSTEST using NUnit.Framework; #else @@ -38,7 +42,7 @@ namespace MsgPack.Serialization { [TestFixture] - [Timeout( 15000 )] + //[Timeout( 15000 )] public class SerializationContextTest { [Test] @@ -88,7 +92,9 @@ public void TestDefaultCollectionTypes_Default_Check() { var context = new SerializationContext(); Assert.That( context.DefaultCollectionTypes.Get( typeof( IList<> ) ), Is.EqualTo( typeof( List<> ) ) ); +#if !NETFX_35 Assert.That( context.DefaultCollectionTypes.Get( typeof( ISet<> ) ), Is.EqualTo( typeof( HashSet<> ) ) ); +#endif Assert.That( context.DefaultCollectionTypes.Get( typeof( ICollection<> ) ), Is.EqualTo( typeof( List<> ) ) ); Assert.That( context.DefaultCollectionTypes.Get( typeof( IEnumerable<> ) ), Is.EqualTo( typeof( List<> ) ) ); Assert.That( context.DefaultCollectionTypes.Get( typeof( IDictionary<,> ) ), Is.EqualTo( typeof( Dictionary<,> ) ) ); @@ -182,6 +188,87 @@ public void TestDefaultCollectionTypes_Register_CloseOpen_Fail() Assert.Throws( () => context.DefaultCollectionTypes.Register( typeof( IList ), typeof( List<> ) ) ); } + [Test] + public void TestIssue24() + { + var context = new SerializationContext(); + context.Serializers.RegisterOverride( new NetDateTimeSerializer() ); + using ( var buffer = new MemoryStream() ) + { + var serializer = MessagePackSerializer.Create( context ); + var dt = new DateTime( 999999999999999999L, DateTimeKind.Utc ); + serializer.Pack( buffer, dt ); + buffer.Position = 0; + var result = serializer.Unpack( buffer ); + Assert.That( result, Is.EqualTo( dt ) ); + } + } + + [Test] + public void TestIssue27_Dictionary() + { + var context = new SerializationContext(); + using ( var buffer = new MemoryStream() ) + { + var serializer = MessagePackSerializer.Create>( context ); + var dic = new Dictionary { { "A", "A" } }; + serializer.Pack( buffer, dic ); + buffer.Position = 0; + + var result = serializer.Unpack( buffer ); + + Assert.That( result.Count, Is.EqualTo( 1 ) ); + Assert.That( result[ "A" ], Is.EqualTo( "A" ) ); + } + } + + [Test] + public void TestIssue27_List() + { + var context = new SerializationContext(); + using ( var buffer = new MemoryStream() ) + { + var serializer = MessagePackSerializer.Create>( context ); + var list = new List { "A" }; + serializer.Pack( buffer, list ); + buffer.Position = 0; + var result = serializer.Unpack( buffer ); + + Assert.That( result.Count, Is.EqualTo( 1 ) ); + Assert.That( result[ 0 ], Is.EqualTo( "A" ) ); + } + } + + + [Test] + public void TestIssue27_Collection() + { + var context = new SerializationContext(); + using ( var buffer = new MemoryStream() ) + { + var serializer = MessagePackSerializer.Create>( context ); + var list = new List { "A" }; + serializer.Pack( buffer, list ); + buffer.Position = 0; + var result = serializer.Unpack( buffer ); + + Assert.That( result.Count, Is.EqualTo( 1 ) ); + Assert.That( result.First(), Is.EqualTo( "A" ) ); + } + } + private sealed class NetDateTimeSerializer : MessagePackSerializer + { + protected internal override void PackToCore( Packer packer, DateTime objectTree ) + { + packer.Pack( objectTree.ToUniversalTime().Ticks ); + } + + protected internal override DateTime UnpackFromCore( Unpacker unpacker ) + { + return new DateTime( unpacker.LastReadData.AsInt64(), DateTimeKind.Utc ); + } + } + private sealed class ConcurrentHelper : IDisposable where T : class { @@ -250,7 +337,7 @@ private void TestValue() public abstract class NewAbstractCollection : Collection { - + } public sealed class NewConcreteCollection : NewAbstractCollection diff --git a/test/MsgPack.UnitTest/Serialization/SerializerGeneratorTest.cs b/test/MsgPack.UnitTest/Serialization/SerializerGeneratorTest.cs index e7e0e7118..e8d11b87d 100644 --- a/test/MsgPack.UnitTest/Serialization/SerializerGeneratorTest.cs +++ b/test/MsgPack.UnitTest/Serialization/SerializerGeneratorTest.cs @@ -241,7 +241,7 @@ public void DoTest( string testAssemblyFile, int packerCompatiblityOptions, byte { var assembly = Assembly.LoadFrom( testAssemblyFile ); var types = assembly.GetTypes().Where( t => typeof( IMessagePackSerializer ).IsAssignableFrom( t ) ).ToList(); - Assert.That( types.Count, Is.EqualTo( expectedSerializerTypeCounts ), String.Join( ", ", types ) ); + Assert.That( types.Count, Is.EqualTo( expectedSerializerTypeCounts ), String.Join( ", ", types.Select( t => t.ToString() ).ToArray() ) ); var context = new SerializationContext( ( PackerCompatibilityOptions )packerCompatiblityOptions );