Skip to content

Commit fb1db57

Browse files
committed
Refactor serializer generation layer to simplify exceptional flow.
1 parent abf5f49 commit fb1db57

21 files changed

Lines changed: 49 additions & 67 deletions

src/MsgPack/Serialization/AbstractSerializers/ISerializerBuilder.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,12 @@ internal interface ISerializerBuilder<TObject>
3333
/// Builds the serializer and returns its new instance.
3434
/// </summary>
3535
/// <param name="context">The context information.</param>
36+
/// <param name="concreteType">The substitution type if <typeparamref name="TObject"/> is abstract type. <c>null</c> when <typeparamref name="TObject"/> is not abstract type.</param>
3637
/// <param name="schema">The schema which contains schema for collection items, dictionary keys, or tuple items. This value may be <c>null</c>.</param>
3738
/// <returns>
3839
/// Newly created serializer object.
3940
/// This value will not be <c>null</c>.
4041
/// </returns>
41-
MessagePackSerializer<TObject> BuildSerializerInstance( SerializationContext context, PolymorphismSchema schema );
42+
MessagePackSerializer<TObject> BuildSerializerInstance( SerializationContext context, Type concreteType, PolymorphismSchema schema );
4243
}
4344
}

src/MsgPack/Serialization/AbstractSerializers/ISerializerCodeGenerator.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,14 @@ internal interface ISerializerCodeGenerator
3434
/// <param name="context">
3535
/// The <see cref="ISerializerCodeGenerationContext"/> which holds configuration and stores generated code constructs.
3636
/// </param>
37+
/// <param name="concreteType">The substitution type if builder's target type is abstract type. <c>null</c> when builder's target type is not abstract type.</param>
3738
/// <param name="itemSchema">The schema which contains schema for collection items, dictionary keys, or tuple items. This value must not be <c>null</c>.</param>
3839
/// <exception cref="ArgumentNullException">
3940
/// <paramref name="context"/> is <c>null</c>.
4041
/// </exception>
4142
/// <exception cref="NotSupportedException">
4243
/// This class does not support code generation.
4344
/// </exception>
44-
void BuildSerializerCode( ISerializerCodeGenerationContext context, PolymorphismSchema itemSchema );
45+
void BuildSerializerCode( ISerializerCodeGenerationContext context, Type concreteType, PolymorphismSchema itemSchema );
4546
}
4647
}

src/MsgPack/Serialization/AbstractSerializers/SerializerBuilderContract`3.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ protected override TContext CreateCodeGenerationContextForSerializerCreation( Se
4141
}
4242

4343
#if !NETFX_CORE && !SILVERLIGHT
44-
protected override void BuildSerializerCodeCore( ISerializerCodeGenerationContext context, PolymorphismSchema itemSchema )
44+
protected override void BuildSerializerCodeCore( ISerializerCodeGenerationContext context, Type concreteType, PolymorphismSchema itemSchema )
4545
{
4646
Contract.Requires( context != null );
4747
}

src/MsgPack/Serialization/AbstractSerializers/SerializerBuilder`3.Array.cs

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ namespace MsgPack.Serialization.AbstractSerializers
2525
{
2626
partial class SerializerBuilder<TContext, TConstruct, TObject>
2727
{
28-
private void BuildArraySerializer( TContext context, CollectionTraits traits, PolymorphismSchema itemsSchema )
28+
private void BuildArraySerializer( TContext context, Type concreteType, CollectionTraits traits, PolymorphismSchema itemsSchema )
2929
{
3030
this.BuildCollectionPackTo( context, traits, itemsSchema );
31-
this.BuildCollectionUnpackFrom( context, traits, itemsSchema );
31+
this.BuildCollectionUnpackFrom( context, concreteType, traits, itemsSchema );
3232
if ( traits.AddMethod != null )
3333
{
3434
this.BuildCollectionUnpackTo( context, traits, itemsSchema );
@@ -99,26 +99,14 @@ private TConstruct EmitInvokeEnumerableToArrayExpression( TContext context, TCon
9999
return this.EmitInvokeMethodExpression( context, null, Metadata._Enumerable.ToArray1Method.MakeGenericMethod( elementType ), enumerable );
100100
}
101101

102-
private void BuildCollectionUnpackFrom( TContext context, CollectionTraits traits, PolymorphismSchema itemsSchema )
102+
private void BuildCollectionUnpackFrom( TContext context, Type concreteType, CollectionTraits traits, PolymorphismSchema itemsSchema )
103103
{
104104
this.EmitMethodPrologue( context, SerializerMethod.UnpackFromCore );
105105

106106
TConstruct construct = null;
107107
try
108108
{
109-
Type instanceType;
110-
if ( typeof( TObject ).GetIsInterface() || typeof( TObject ).GetIsAbstract() )
111-
{
112-
instanceType = context.SerializationContext.DefaultCollectionTypes.GetConcreteType( typeof( TObject ) );
113-
if ( instanceType == null )
114-
{
115-
throw SerializationExceptions.NewNotSupportedBecauseCannotInstanciateAbstractType( typeof( TObject ) );
116-
}
117-
}
118-
else
119-
{
120-
instanceType = typeof( TObject );
121-
}
109+
var instanceType = concreteType ?? typeof( TObject );
122110

123111
/*
124112
* if (!unpacker.IsArrayHeader)

src/MsgPack/Serialization/AbstractSerializers/SerializerBuilder`3.Map.cs

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ namespace MsgPack.Serialization.AbstractSerializers
2626
{
2727
partial class SerializerBuilder<TContext, TConstruct, TObject>
2828
{
29-
private void BuildMapSerializer( TContext context, CollectionTraits traits, PolymorphismSchema keysSchema, PolymorphismSchema valuesSchema )
29+
private void BuildMapSerializer( TContext context, Type concreteType, CollectionTraits traits, PolymorphismSchema keysSchema, PolymorphismSchema valuesSchema )
3030
{
3131
this.BuildMapPackTo( context, traits, keysSchema, valuesSchema );
32-
this.BuildMapUnpackFrom( context );
32+
this.BuildMapUnpackFrom( context, concreteType );
3333
this.BuildMapUnpackTo( context, traits, keysSchema, valuesSchema );
3434
}
3535

@@ -121,25 +121,13 @@ private TConstruct EmitPackKeyValuePair( TContext context, CollectionTraits trai
121121
);
122122
}
123123

124-
private void BuildMapUnpackFrom( TContext context )
124+
private void BuildMapUnpackFrom( TContext context, Type concreteType )
125125
{
126126
this.EmitMethodPrologue( context, SerializerMethod.UnpackFromCore );
127127
TConstruct construct = null;
128128
try
129129
{
130-
Type instanceType;
131-
if ( typeof( TObject ).GetIsInterface() || typeof( TObject ).GetIsAbstract() )
132-
{
133-
instanceType = context.SerializationContext.DefaultCollectionTypes.GetConcreteType( typeof( TObject ) );
134-
if ( instanceType == null )
135-
{
136-
throw SerializationExceptions.NewNotSupportedBecauseCannotInstanciateAbstractType( typeof( TObject ) );
137-
}
138-
}
139-
else
140-
{
141-
instanceType = typeof( TObject );
142-
}
130+
var instanceType = concreteType ?? typeof( TObject );
143131

144132
/*
145133
* if (!unpacker.IsMapHeader)

src/MsgPack/Serialization/AbstractSerializers/SerializerBuilder`3.cs

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@
2121
using System;
2222
using System.Diagnostics.Contracts;
2323

24-
using MsgPack.Serialization.DefaultSerializers;
25-
2624
namespace MsgPack.Serialization.AbstractSerializers
2725
{
2826
/// <summary>
@@ -52,20 +50,15 @@ protected SerializerBuilder() { }
5250
/// Builds the serializer and returns its new instance.
5351
/// </summary>
5452
/// <param name="context">The context information.</param>
53+
/// <param name="concreteType">The substitution type if <typeparamref name="TObject"/> is abstract type. <c>null</c> when <typeparamref name="TObject"/> is not abstract type.</param>
5554
/// <param name="schema">The schema which contains schema for collection items, dictionary keys, or tuple items. This value may be <c>null</c>.</param>
5655
/// <returns>
5756
/// Newly created serializer object.
5857
/// This value will not be <c>null</c>.
5958
/// </returns>
6059
[System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods", MessageId = "0", Justification = "Asserted internally" )]
61-
public MessagePackSerializer<TObject> BuildSerializerInstance( SerializationContext context, PolymorphismSchema schema )
60+
public MessagePackSerializer<TObject> BuildSerializerInstance( SerializationContext context, Type concreteType, PolymorphismSchema schema )
6261
{
63-
var genericSerializer = GenericSerializer.Create<TObject>( context, schema );
64-
if ( genericSerializer != null )
65-
{
66-
return genericSerializer;
67-
}
68-
6962
Func<SerializationContext, MessagePackSerializer<TObject>> constructor;
7063
var codeGenerationContext = this.CreateCodeGenerationContextForSerializerCreation( context );
7164
if ( typeof( TObject ).GetIsEnum() )
@@ -75,7 +68,7 @@ public MessagePackSerializer<TObject> BuildSerializerInstance( SerializationCont
7568
}
7669
else
7770
{
78-
this.BuildSerializer( codeGenerationContext, schema );
71+
this.BuildSerializer( codeGenerationContext, concreteType, schema );
7972
constructor = this.CreateSerializerConstructor( codeGenerationContext );
8073
}
8174

@@ -105,12 +98,13 @@ public MessagePackSerializer<TObject> BuildSerializerInstance( SerializationCont
10598
/// Builds the serializer and returns its new instance.
10699
/// </summary>
107100
/// <param name="context">The context information. This value will not be <c>null</c>.</param>
101+
/// <param name="concreteType">The substitution type if <typeparamref name="TObject"/> is abstract type. <c>null</c> when <typeparamref name="TObject"/> is not abstract type.</param>
108102
/// <param name="schema">The schema which contains schema for collection items, dictionary keys, or tuple items. This value may be <c>null</c>.</param>
109103
/// <returns>
110104
/// Newly created serializer object.
111105
/// This value will not be <c>null</c>.
112106
/// </returns>
113-
protected void BuildSerializer( TContext context, PolymorphismSchema schema )
107+
protected void BuildSerializer( TContext context, Type concreteType, PolymorphismSchema schema )
114108
{
115109
#if DEBUG
116110
Contract.Assert( !typeof( TObject ).IsArray );
@@ -121,13 +115,13 @@ protected void BuildSerializer( TContext context, PolymorphismSchema schema )
121115
{
122116
case CollectionKind.Array:
123117
{
124-
this.BuildArraySerializer( context, traits, ( schema ?? PolymorphismSchema.Default ).ItemSchema );
118+
this.BuildArraySerializer( context, concreteType, traits, ( schema ?? PolymorphismSchema.Default ).ItemSchema );
125119
break;
126120
}
127121
case CollectionKind.Map:
128122
{
129123
var itemSchema = ( schema ?? PolymorphismSchema.Default );
130-
this.BuildMapSerializer( context, traits, itemSchema.KeySchema, itemSchema.ItemSchema );
124+
this.BuildMapSerializer( context, concreteType, traits, itemSchema.KeySchema, itemSchema.ItemSchema );
131125
break;
132126
}
133127
case CollectionKind.NotCollection:
@@ -186,6 +180,7 @@ TContext codeGenerationContext
186180
/// <param name="context">
187181
/// The <see cref="ISerializerCodeGenerationContext"/> which holds configuration and stores generated code constructs.
188182
/// </param>
183+
/// <param name="concreteType">The substitution type if <typeparamref name="TObject"/> is abstract type. <c>null</c> when <typeparamref name="TObject"/> is not abstract type.</param>
189184
/// <param name="itemSchema">The schema which contains schema for collection items, dictionary keys, or tuple items. This value must not be <c>null</c>.</param>
190185
/// <exception cref="ArgumentNullException">
191186
/// <paramref name="context"/> is <c>null</c>.
@@ -196,7 +191,7 @@ TContext codeGenerationContext
196191
/// <remarks>
197192
/// This method will not do anything when <see cref="ISerializerCodeGenerationContext.BuiltInSerializerExists"/> returns <c>true</c> for <typeparamref name="TObject"/>.
198193
/// </remarks>
199-
public void BuildSerializerCode( ISerializerCodeGenerationContext context, PolymorphismSchema itemSchema )
194+
public void BuildSerializerCode( ISerializerCodeGenerationContext context, Type concreteType, PolymorphismSchema itemSchema )
200195
{
201196
if ( context == null )
202197
{
@@ -209,7 +204,7 @@ public void BuildSerializerCode( ISerializerCodeGenerationContext context, Polym
209204
return;
210205
}
211206

212-
this.BuildSerializerCodeCore( context, itemSchema );
207+
this.BuildSerializerCodeCore( context, concreteType, itemSchema );
213208
}
214209

215210
/// <summary>
@@ -219,11 +214,12 @@ public void BuildSerializerCode( ISerializerCodeGenerationContext context, Polym
219214
/// The <see cref="ISerializerCodeGenerationContext"/> which holds configuration and stores generated code constructs.
220215
/// This value will not be <c>null</c>.
221216
/// </param>
217+
/// <param name="concreteType">The substitution type if <typeparamref name="TObject"/> is abstract type. <c>null</c> when <typeparamref name="TObject"/> is not abstract type.</param>
222218
/// <param name="itemSchema">The schema which contains schema for collection items, dictionary keys, or tuple items. This value must not be <c>null</c>.</param>
223219
/// <exception cref="NotSupportedException">
224220
/// This class does not support code generation.
225221
/// </exception>
226-
protected virtual void BuildSerializerCodeCore( ISerializerCodeGenerationContext context, PolymorphismSchema itemSchema )
222+
protected virtual void BuildSerializerCodeCore( ISerializerCodeGenerationContext context, Type concreteType, PolymorphismSchema itemSchema )
227223
{
228224
throw new NotSupportedException();
229225
}

src/MsgPack/Serialization/CodeDomSerializers/CodeDomSerializerBuilder`1.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -907,7 +907,7 @@ protected override CodeDomConstruct EmitEnumToUnderlyingCastExpression(
907907
return CodeDomConstruct.Expression( underlyingType, new CodeCastExpression( underlyingType, enumValue.AsExpression() ) );
908908
}
909909

910-
protected override void BuildSerializerCodeCore( ISerializerCodeGenerationContext context, PolymorphismSchema itemSchema )
910+
protected override void BuildSerializerCodeCore( ISerializerCodeGenerationContext context, Type concreteType, PolymorphismSchema itemSchema )
911911
{
912912
var asCodeDomContext = context as CodeDomContext;
913913
if ( asCodeDomContext == null )
@@ -920,7 +920,7 @@ protected override void BuildSerializerCodeCore( ISerializerCodeGenerationContex
920920

921921
asCodeDomContext.Reset( typeof( TObject ) );
922922

923-
this.BuildSerializer( asCodeDomContext, itemSchema );
923+
this.BuildSerializer( asCodeDomContext, concreteType, itemSchema );
924924
this.Finish( asCodeDomContext, typeof( TObject ).GetIsEnum() );
925925
}
926926

src/MsgPack/Serialization/EmittingSerializers/AssemblyBuilderSerializerBuilder`1.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ protected override AssemblyBuilderEmittingContext CreateCodeGenerationContextFor
126126
}
127127

128128
#if !SILVERLIGHT
129-
protected override void BuildSerializerCodeCore( ISerializerCodeGenerationContext context, PolymorphismSchema itemSchema )
129+
protected override void BuildSerializerCodeCore( ISerializerCodeGenerationContext context, Type concreteType, PolymorphismSchema itemSchema )
130130
{
131131
var asAssemblyBuilderCodeGenerationContext = context as AssemblyBuilderCodeGenerationContext;
132132
if ( asAssemblyBuilderCodeGenerationContext == null )
@@ -142,7 +142,7 @@ protected override void BuildSerializerCodeCore( ISerializerCodeGenerationContex
142142
typeof( TObject )
143143
);
144144

145-
this.BuildSerializer( emittingContext, itemSchema );
145+
this.BuildSerializer( emittingContext, concreteType, itemSchema );
146146
// Finish type creation, and discard returned ctor.
147147
emittingContext.Emitter.CreateConstructor<TObject>();
148148
}

src/MsgPack/Serialization/MessagePackSerializer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ internal static MessagePackSerializer<T> CreateInternal<T>( SerializationContext
301301
#endif // !XAMIOS && !XAMDROID && !UNITY
302302
#endif // NETFX_CORE else
303303
#if !XAMIOS && !XAMDROID && !UNITY
304-
return builder.BuildSerializerInstance( context, schema == null ? null : schema.FilterSelf() );
304+
return builder.BuildSerializerInstance( context, concreteType, schema == null ? null : schema.FilterSelf() );
305305
#endif // !XAMIOS && !XAMDROID && !UNITY
306306
}
307307

src/MsgPack/Serialization/SerializerGenerator.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,14 @@ public IEnumerable<string> Generate( IEnumerable<Type> targetTypes, TConfig conf
343343
foreach ( var targetType in targetTypes.Distinct() )
344344
{
345345
var generator = generatorFactory( targetType );
346-
generator.BuildSerializerCode( generationContext, null );
346+
347+
var concreteType = default( Type );
348+
if ( targetType.GetIsInterface() || targetType.GetIsAbstract() )
349+
{
350+
concreteType = context.DefaultCollectionTypes.GetConcreteType( targetType );
351+
}
352+
353+
generator.BuildSerializerCode( generationContext, concreteType, null );
347354
}
348355

349356
Directory.CreateDirectory( configuration.OutputDirectory );

0 commit comments

Comments
 (0)