Skip to content

Commit a82bd9a

Browse files
author
Robert Stam
committed
Merged pull request for CSHARP-451 with changes. Restored explicit registration of default serialization provider. Registering a serializer for any type that implements IBsonSerializable is not allowed for performance reasons.
1 parent 8c4d787 commit a82bd9a

File tree

3 files changed

+60
-43
lines changed

3 files changed

+60
-43
lines changed

Bson/Serialization/BsonClassMap.cs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -968,18 +968,20 @@ public void UnmapProperty(string propertyName)
968968

969969
// internal methods
970970
/// <summary>
971-
/// Gets the discriminator convention for the member type.
971+
/// Gets the discriminator convention for the class.
972972
/// </summary>
973-
/// <returns>The discriminator convention for the member type.</returns>
973+
/// <returns>The discriminator convention for the class.</returns>
974974
internal IDiscriminatorConvention GetDiscriminatorConvention()
975975
{
976-
var classDiscriminatorConvention = _cachedDiscriminatorConvention;
977-
if (classDiscriminatorConvention == null)
976+
// return a cached discriminator convention when possible
977+
var discriminatorConvention = _cachedDiscriminatorConvention;
978+
if (discriminatorConvention == null)
978979
{
979-
classDiscriminatorConvention = BsonDefaultSerializer.LookupDiscriminatorConvention(_classType);
980-
_cachedDiscriminatorConvention = classDiscriminatorConvention;
980+
// it's possible but harmless for multiple threads to do the initial lookup at the same time
981+
discriminatorConvention = BsonDefaultSerializer.LookupDiscriminatorConvention(_classType);
982+
_cachedDiscriminatorConvention = discriminatorConvention;
981983
}
982-
return classDiscriminatorConvention;
984+
return discriminatorConvention;
983985
}
984986

985987
// private methods

Bson/Serialization/BsonMemberMap.cs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -287,21 +287,24 @@ public void ApplyDefaultValue(object obj)
287287
/// <returns>The member map.</returns>
288288
public IBsonSerializer GetSerializer(Type actualType)
289289
{
290+
// if a custom serializer is configured always return it
290291
if (_serializer != null)
291292
{
292293
return _serializer;
293294
}
294295
else
295296
{
297+
// return a cached serializer when possible
296298
if (actualType == _memberType)
297299
{
298-
var cachedSerializer = _cachedSerializer;
299-
if (cachedSerializer == null)
300+
var serializer = _cachedSerializer;
301+
if (serializer == null)
300302
{
301-
cachedSerializer = BsonSerializer.LookupSerializer(_memberType);
302-
_cachedSerializer = cachedSerializer;
303+
// it's possible but harmless for multiple threads to do the initial lookup at the same time
304+
serializer = BsonSerializer.LookupSerializer(_memberType);
305+
_cachedSerializer = serializer;
303306
}
304-
return cachedSerializer;
307+
return serializer;
305308
}
306309
else
307310
{
@@ -505,13 +508,15 @@ public bool ShouldSerialize(object obj, object value)
505508
/// <returns>The discriminator convention for the member type.</returns>
506509
internal IDiscriminatorConvention GetDiscriminatorConvention()
507510
{
508-
var classDiscriminatorConvention = _cachedDiscriminatorConvention;
509-
if (classDiscriminatorConvention == null)
511+
// return a cached discriminator convention when possible
512+
var discriminatorConvention = _cachedDiscriminatorConvention;
513+
if (discriminatorConvention == null)
510514
{
511-
classDiscriminatorConvention = BsonDefaultSerializer.LookupDiscriminatorConvention(_memberType);
512-
_cachedDiscriminatorConvention = classDiscriminatorConvention;
515+
// it's possible but harmless for multiple threads to do the initial lookup at the same time
516+
discriminatorConvention = BsonDefaultSerializer.LookupDiscriminatorConvention(_memberType);
517+
_cachedDiscriminatorConvention = discriminatorConvention;
513518
}
514-
return classDiscriminatorConvention;
519+
return discriminatorConvention;
515520
}
516521

517522
// private methods

Bson/Serialization/BsonSerializer.cs

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ public static class BsonSerializer
4343
// static constructor
4444
static BsonSerializer()
4545
{
46+
RegisterDefaultSerializationProvider();
4647
RegisterIdGenerators();
4748
}
4849

@@ -358,16 +359,22 @@ public static IIdGenerator LookupIdGenerator(Type type)
358359
}
359360

360361
/// <summary>
361-
/// Looks up and populates the serializer singleton for a type.
362+
/// Looks up a serializer for a Type.
362363
/// </summary>
363364
/// <param name="type">The Type.</param>
364365
/// <returns>A serializer for the Type.</returns>
365366
public static IBsonSerializer LookupSerializer(Type type)
366367
{
368+
// since we don't allow registering serializers for classes that implement IBsonSerializable no lookup is needed
369+
if (typeof(IBsonSerializable).IsAssignableFrom(type))
370+
{
371+
return Serializers.BsonIBsonSerializableSerializer.Instance;
372+
}
373+
367374
__configLock.EnterReadLock();
368375
try
369376
{
370-
IBsonSerializer serializer;
377+
IBsonSerializer serializer;
371378
if (__serializers.TryGetValue(type, out serializer))
372379
{
373380
return serializer;
@@ -384,24 +391,6 @@ public static IBsonSerializer LookupSerializer(Type type)
384391
IBsonSerializer serializer;
385392
if (!__serializers.TryGetValue(type, out serializer))
386393
{
387-
if (serializer == null)
388-
{
389-
foreach (var serializationProvider in __serializationProviders)
390-
{
391-
serializer = serializationProvider.GetSerializer(type);
392-
if (serializer != null)
393-
{
394-
break;
395-
}
396-
}
397-
}
398-
399-
// special case for IBsonSerializable
400-
if (serializer == null && typeof(IBsonSerializable).IsAssignableFrom(type))
401-
{
402-
serializer = Serializers.BsonIBsonSerializableSerializer.Instance;
403-
}
404-
405394
if (serializer == null && type.IsGenericType)
406395
{
407396
var genericTypeDefinition = type.GetGenericTypeDefinition();
@@ -415,7 +404,14 @@ public static IBsonSerializer LookupSerializer(Type type)
415404

416405
if (serializer == null)
417406
{
418-
serializer = BsonDefaultSerializer.Instance.GetSerializer(type);
407+
foreach (var serializationProvider in __serializationProviders)
408+
{
409+
serializer = serializationProvider.GetSerializer(type);
410+
if (serializer != null)
411+
{
412+
break;
413+
}
414+
}
419415
}
420416

421417
if (serializer == null)
@@ -479,11 +475,6 @@ public static void RegisterIdGenerator(Type type, IIdGenerator idGenerator)
479475
/// <param name="provider">The serialization provider.</param>
480476
public static void RegisterSerializationProvider(IBsonSerializationProvider provider)
481477
{
482-
if (provider == BsonDefaultSerializer.Instance)
483-
{
484-
throw new ArgumentException("BsonDefaultSerializer is implicitly registered", "provider");
485-
}
486-
487478
__configLock.EnterWriteLock();
488479
try
489480
{
@@ -503,6 +494,12 @@ public static void RegisterSerializationProvider(IBsonSerializationProvider prov
503494
/// <param name="serializer">The serializer.</param>
504495
public static void RegisterSerializer(Type type, IBsonSerializer serializer)
505496
{
497+
if (typeof(IBsonSerializable).IsAssignableFrom(type))
498+
{
499+
var message = string.Format("A serializer cannot be registered for type {0} because it implements IBsonSerializable.", BsonUtils.GetFriendlyTypeName(type));
500+
throw new BsonSerializationException(message);
501+
}
502+
506503
__configLock.EnterWriteLock();
507504
try
508505
{
@@ -569,12 +566,25 @@ public static void Serialize(
569566
object value,
570567
IBsonSerializationOptions options)
571568
{
569+
// since we don't allow registering serializers for classes that implement IBsonSerializable no lookup is needed
570+
var bsonSerializable = value as IBsonSerializable;
571+
if (bsonSerializable != null)
572+
{
573+
bsonSerializable.Serialize(bsonWriter, nominalType, options);
574+
return;
575+
}
576+
572577
var actualType = (value == null) ? nominalType : value.GetType();
573578
var serializer = LookupSerializer(actualType);
574579
serializer.Serialize(bsonWriter, nominalType, value, options);
575580
}
576581

577582
// private static methods
583+
private static void RegisterDefaultSerializationProvider()
584+
{
585+
RegisterSerializationProvider(BsonDefaultSerializer.Instance);
586+
}
587+
578588
private static void RegisterIdGenerators()
579589
{
580590
BsonSerializer.RegisterIdGenerator(typeof(BsonObjectId), BsonObjectIdGenerator.Instance);

0 commit comments

Comments
 (0)