@@ -17,14 +17,18 @@ namespace Microsoft.VisualStudio.Composition
1717 using System . Collections . Immutable ;
1818 using System . Diagnostics ;
1919 using System . Diagnostics . CodeAnalysis ;
20- using System . Globalization ;
2120 using System . IO ;
2221 using System . Reflection ;
23- using MessagePack ;
22+ using System . Text . RegularExpressions ;
2423 using Microsoft . VisualStudio . Composition . Reflection ;
24+ using Nerdbank . MessagePack ;
25+ using PolyType ;
26+ using PolyType . ReflectionProvider ;
2527
26- internal abstract class SerializationContextBase : IDisposable
28+ internal abstract partial class SerializationContextBase : IDisposable
2729 {
30+ protected static readonly MessagePackSerializer Serializer = new ( ) ;
31+
2832 protected BinaryReader ? reader ;
2933
3034 protected BinaryWriter ? writer ;
@@ -55,8 +59,6 @@ internal abstract class SerializationContextBase : IDisposable
5559 private static readonly object BoxedTrue = true ;
5660 private static readonly object BoxedFalse = false ;
5761
58- private static readonly MessagePackSerializerOptions MessagePackSerializerOptions = MessagePackSerializerOptions . Standard . WithResolver ( MessagePack . Resolvers . TypelessObjectResolver . Instance ) ;
59-
6062 internal SerializationContextBase ( BinaryReader reader , Resolver resolver )
6163 {
6264 Requires . NotNull ( reader , nameof ( reader ) ) ;
@@ -1059,10 +1061,10 @@ protected void WriteObject(object? value)
10591061 }
10601062 else
10611063 {
1062- Debug . WriteLine ( "Falling back to binary formatter for value of type: {0}" , valueType ) ;
1064+ Debug . WriteLine ( "Falling back to typeless mode for value of type: {0}" , valueType ) ;
10631065 this . Write ( ObjectType . BinaryFormattedObject ) ;
10641066 this . writer . Flush ( ) ;
1065- byte [ ] typeLessData = MessagePackSerializer . Typeless . Serialize ( value , MessagePackSerializerOptions ) ;
1067+ byte [ ] typeLessData = Serializer . Serialize ( new TypelessEnvelope ( value ) ) ;
10661068 this . writer . Write ( typeLessData . Length ) ;
10671069 this . writer . Write ( typeLessData ) ;
10681070 }
@@ -1135,7 +1137,7 @@ protected void WriteObject(object? value)
11351137 case ObjectType . BinaryFormattedObject :
11361138 int typelessDataLength = this . reader . ReadInt32 ( ) ;
11371139 byte [ ] bytes = this . reader . ReadBytes ( typelessDataLength ) ;
1138- return MessagePackSerializer . Typeless . Deserialize ( bytes , MessagePackSerializerOptions ) ;
1140+ return Serializer . Deserialize < TypelessEnvelope > ( bytes ) . Value ;
11391141 default :
11401142 throw new NotSupportedException ( Strings . FormatUnsupportedFormat ( objectType ) ) ;
11411143 }
@@ -1167,6 +1169,56 @@ protected void TraceStats()
11671169#endif
11681170 }
11691171
1172+ [ GenerateShape ]
1173+ [ MessagePackConverter ( typeof ( TypelessEnvelopeConverter ) ) ]
1174+ internal readonly partial struct TypelessEnvelope ( object value )
1175+ {
1176+ public object Value { get ; } = value ;
1177+ }
1178+
1179+ internal class TypelessEnvelopeConverter : MessagePackConverter < TypelessEnvelope >
1180+ {
1181+ // see:http://msdn.microsoft.com/en-us/library/w3f99sx1.aspx
1182+ private static readonly Regex AssemblyNameVersionSelectorRegex = new ( @", Version=\d+.\d+.\d+.\d+, Culture=[\w-]+, PublicKeyToken=(?:null|[a-f0-9]{16})" , RegexOptions . Compiled ) ;
1183+
1184+ public override TypelessEnvelope Read ( ref MessagePackReader reader , SerializationContext context )
1185+ {
1186+ if ( reader . ReadArrayHeader ( ) != 2 )
1187+ {
1188+ throw new MessagePackSerializationException ( "Invalid TypelessEnvelope format." ) ;
1189+ }
1190+
1191+ string typeName = reader . ReadString ( ) ?? throw new MessagePackSerializationException ( "Invalid TypelessEnvelope format." ) ;
1192+ Type type = LoadType ( typeName ) ;
1193+ MessagePackConverter converter = context . GetConverter ( type , ReflectionTypeShapeProvider . Default ) ;
1194+ object value = converter . ReadObject ( ref reader , context ) ! ;
1195+ return new TypelessEnvelope ( value ) ;
1196+ }
1197+
1198+ public override void Write ( ref MessagePackWriter writer , in TypelessEnvelope value , SerializationContext context )
1199+ {
1200+ writer . WriteArrayHeader ( 2 ) ;
1201+ writer . Write ( value . Value . GetType ( ) . AssemblyQualifiedName ) ;
1202+ MessagePackConverter converter = context . GetConverter ( value . Value . GetType ( ) , ReflectionTypeShapeProvider . Default ) ;
1203+ converter . WriteObject ( ref writer , value . Value , context ) ;
1204+ }
1205+
1206+ private static Type LoadType ( string typeName )
1207+ {
1208+ Type ? result = Type . GetType ( typeName , false ) ;
1209+ if ( result is null )
1210+ {
1211+ string shortenedName = AssemblyNameVersionSelectorRegex . Replace ( typeName , string . Empty ) ;
1212+ if ( shortenedName != typeName )
1213+ {
1214+ result = Type . GetType ( shortenedName , false ) ;
1215+ }
1216+ }
1217+
1218+ return result ?? throw new InvalidOperationException ( $ "Unable to load type \" { typeName } \" .") ;
1219+ }
1220+ }
1221+
11701222 protected struct SerializationTrace : IDisposable
11711223 {
11721224 private const string Indent = " " ;
0 commit comments