diff --git a/Bson/Bson.csproj b/Bson/Bson.csproj
index ad661bedb2d..da3e857e074 100644
--- a/Bson/Bson.csproj
+++ b/Bson/Bson.csproj
@@ -83,6 +83,7 @@
Properties\GlobalAssemblyInfo.cs
+
diff --git a/Bson/FastSingleton.cs b/Bson/FastSingleton.cs
new file mode 100644
index 00000000000..f50486c2e12
--- /dev/null
+++ b/Bson/FastSingleton.cs
@@ -0,0 +1,251 @@
+/* Copyright 2010-2012 10gen Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Threading;
+
+namespace MongoDB.Bson
+{
+ ///
+ /// Fast singleton abstract base class. Enables runtime, static, and lazy binding.
+ ///
+ /// The singleton value type.
+ internal abstract class FastSingleton where TValue : class
+ {
+ // private static fields
+ private static ReaderWriterLockSlim __readerWriterLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
+ private static Dictionary> __dictionary = new Dictionary>();
+
+ // public properties
+ ///
+ /// Gets the singleton value.
+ ///
+ public abstract TValue Value
+ {
+ get;
+ }
+
+ ///
+ /// Gets An optional user-defined object that contains information about the singleton value.
+ ///
+ public abstract object State
+ {
+ get;
+ }
+
+ // public static methods
+ ///
+ /// Resolves a nominal type to a singleton instance.
+ ///
+ /// The nominal type.
+ /// A singleton instance.
+ public static FastSingleton Lookup(Type nominalType)
+ {
+ FastSingleton value;
+
+ __readerWriterLock.EnterUpgradeableReadLock();
+ try
+ {
+ if (__dictionary.TryGetValue(nominalType, out value))
+ {
+ return value;
+ }
+
+ __readerWriterLock.EnterWriteLock();
+ try
+ {
+ if (__dictionary.TryGetValue(nominalType, out value))
+ {
+ return value;
+ }
+
+ var genericType = typeof(FastSingleton<,>).MakeGenericType(typeof(TValue), nominalType);
+
+ var instancePropertyInfo = genericType.GetProperty(
+ "Instance",
+ BindingFlags.Static | BindingFlags.Public);
+
+ value = (FastSingleton)instancePropertyInfo.GetValue(null, null);
+
+ __dictionary.Add(nominalType, value);
+
+ return value;
+ }
+ finally
+ {
+ __readerWriterLock.ExitWriteLock();
+ }
+ }
+ finally
+ {
+ __readerWriterLock.ExitUpgradeableReadLock();
+ }
+ }
+
+ // public methods
+ ///
+ /// Sets the singleton value.
+ ///
+ /// The singleton value
+ /// An optional user-defined object that contains information about the singleton value.
+ /// Function is atomic.
+ /// true if the singleton value was set; otherwise false.
+ public abstract bool TrySetValue(TValue value, object state);
+
+ // protected classes
+ ///
+ /// Groups a singleton value and user-defined object so they can be set atomically.
+ ///
+ protected class ValueStateTuple
+ {
+ // private fields
+ private readonly TValue value;
+ private readonly object state;
+
+ // constructors
+ ///
+ /// Initializes a new instance of the Tuple class.
+ ///
+ /// The singleton value
+ /// An optional user-defined object that contains information about the singleton value.
+ public ValueStateTuple(TValue value, object state)
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("value");
+ }
+
+ this.value = value;
+ this.state = state;
+ }
+
+ // public properties
+ ///
+ /// Gets the singleton value.
+ ///
+ public TValue Value
+ {
+ get
+ {
+ return this.value;
+ }
+ }
+
+ ///
+ /// Gets an optional user-defined object that contains information about the singleton value.
+ ///
+ public object State
+ {
+ get
+ {
+ return this.state;
+ }
+ }
+ }
+ }
+
+ ///
+ /// Fast singleton implementation class
+ ///
+ /// The singleton value type.
+ /// The nominal type associated with the singleton value.
+ internal sealed class FastSingleton : FastSingleton where TValue : class
+ {
+ // private static fields
+ private static readonly FastSingleton __instance = new FastSingleton();
+ private static ValueStateTuple __tuple; // volatile accesses
+
+ // constructors
+ ///
+ /// Initializes a new instance of the FastSingleton<TValue, TNominal> class.
+ ///
+ /// Private because FastSingleton<TValue, TNominal> is a singleton.
+ private FastSingleton()
+ {
+ }
+
+ ///
+ /// Gets the singleton instance of the FastSingleton<TValue, TNominal> type.
+ ///
+ /// Accessed by FastSingleton.Create
+ public static FastSingleton Instance
+ {
+ get
+ {
+ return __instance;
+ }
+ }
+
+ ///
+ /// Gets the singleton value.
+ ///
+ public override TValue Value
+ {
+ get
+ {
+ // see implementation of Thread.VolatileRead();
+ var tuple = __tuple;
+
+ Thread.MemoryBarrier();
+
+ if (tuple == null)
+ {
+ return null;
+ }
+
+ return tuple.Value;
+ }
+ }
+
+ ///
+ /// Gets An optional user-defined object that contains information about the singleton value.
+ ///
+ public override object State
+ {
+ get
+ {
+ // see implementation of Thread.VolatileRead();
+ var tuple = __tuple;
+
+ Thread.MemoryBarrier();
+
+ if (tuple == null)
+ {
+ return null;
+ }
+
+ return tuple.State;
+ }
+ }
+
+ ///
+ /// Sets the singleton value.
+ ///
+ /// The singleton value
+ /// An optional user-defined object that contains information about the singleton value.
+ /// Function is atomic.
+ /// true if the singleton value was set; otherwise false.
+ public override bool TrySetValue(TValue value, object State)
+ {
+ var tuple = new ValueStateTuple(value, State);
+
+ var originalTuple = Interlocked.CompareExchange(ref __tuple, tuple, null);
+
+ return originalTuple == null;
+ }
+ }
+}
diff --git a/Bson/Serialization/BsonClassMap.cs b/Bson/Serialization/BsonClassMap.cs
index 4b5b92c18a2..6b102315b3e 100644
--- a/Bson/Serialization/BsonClassMap.cs
+++ b/Bson/Serialization/BsonClassMap.cs
@@ -62,6 +62,7 @@ public abstract class BsonClassMap
private bool _ignoreExtraElementsIsInherited = false;
private BsonMemberMap _extraElementsMemberMap;
private List _knownTypes = new List();
+ private readonly FastSingleton _discriminatorConvention;
// constructors
///
@@ -74,6 +75,7 @@ protected BsonClassMap(Type classType)
_conventions = LookupConventions(classType);
_discriminator = classType.Name;
_isAnonymous = IsAnonymousType(classType);
+ _discriminatorConvention = FastSingleton.Lookup(classType);
}
// public properties
@@ -581,9 +583,35 @@ public BsonClassMap Freeze()
return this;
}
+ ///
+ /// Gets the discriminator convention for the member type.
+ ///
+ /// The discriminator convention for the member type.
+ internal IDiscriminatorConvention GetDiscriminatorConvention()
+ {
+ if (_discriminatorConvention.Value == null)
+ {
+ // LookupDiscriminatorConvention will populate _discriminatorConvention
+ BsonDefaultSerializer.LookupDiscriminatorConvention(_classType);
+ }
+
+ return _discriminatorConvention.Value;
+ }
+
///
/// Gets a member map (only considers members declared in this class).
///
+ /// The MemberInfo.
+ /// The member map.
+ public BsonMemberMap GetMemberMap(MemberInfo memberInfo)
+ {
+ // can be called whether frozen or not
+ return _declaredMemberMaps.Find(m => m.MemberInfo == memberInfo);
+ }
+
+ ///
+ /// Gets a member map.
+ ///
/// The member name.
/// The member map (or null if the member was not found).
public BsonMemberMap GetMemberMap(string memberName)
@@ -1485,7 +1513,7 @@ public void UnmapProperty(Expression> propertyLam
UnmapMember(propertyLambda);
}
- // private methods
+ // private static methods
private static MemberInfo GetMemberInfoFromLambda(Expression> memberLambda)
{
var body = memberLambda.Body;
diff --git a/Bson/Serialization/BsonClassMapSerializer.cs b/Bson/Serialization/BsonClassMapSerializer.cs
index 18bbb9c1d82..cb8e0422611 100755
--- a/Bson/Serialization/BsonClassMapSerializer.cs
+++ b/Bson/Serialization/BsonClassMapSerializer.cs
@@ -23,6 +23,7 @@
using System.Text.RegularExpressions;
using MongoDB.Bson.IO;
+using MongoDB.Bson.Serialization.Conventions;
using MongoDB.Bson.Serialization.Options;
namespace MongoDB.Bson.Serialization
@@ -131,7 +132,15 @@ public object Deserialize(
bsonReader.ReadStartDocument();
var missingElementMemberMaps = new HashSet(classMap.AllMemberMaps); // make a copy!
- var discriminatorConvention = BsonDefaultSerializer.LookupDiscriminatorConvention(nominalType);
+ IDiscriminatorConvention discriminatorConvention;
+ if (actualType == nominalType)
+ {
+ discriminatorConvention = classMap.GetDiscriminatorConvention();
+ }
+ else
+ {
+ discriminatorConvention = BsonDefaultSerializer.LookupDiscriminatorConvention(nominalType);
+ }
while (bsonReader.ReadBsonType() != BsonType.EndOfDocument)
{
var elementName = bsonReader.ReadName();
@@ -443,7 +452,7 @@ private void DeserializeMember(BsonReader bsonReader, object obj, BsonMemberMap
}
else
{
- var discriminatorConvention = BsonDefaultSerializer.LookupDiscriminatorConvention(nominalType);
+ var discriminatorConvention = memberMap.GetDiscriminatorConvention();
actualType = discriminatorConvention.GetActualType(bsonReader, nominalType); // returns nominalType if no discriminator found
}
var serializer = memberMap.GetSerializer(actualType);
diff --git a/Bson/Serialization/BsonDefaultSerializer.cs b/Bson/Serialization/BsonDefaultSerializer.cs
index 51443d6b6dc..fee51278538 100644
--- a/Bson/Serialization/BsonDefaultSerializer.cs
+++ b/Bson/Serialization/BsonDefaultSerializer.cs
@@ -44,7 +44,6 @@ public class BsonDefaultSerializer : IBsonSerializationProvider
private static BsonDefaultSerializer __instance = new BsonDefaultSerializer();
private static Dictionary __serializers;
private static Dictionary __genericSerializerDefinitions;
- private static Dictionary __discriminatorConventions = new Dictionary();
private static Dictionary> __discriminators = new Dictionary>();
private static HashSet __typesWithRegisteredKnownTypes = new HashSet();
private static HashSet __discriminatedTypes = new HashSet();
@@ -242,71 +241,88 @@ public static Type LookupActualType(Type nominalType, BsonValue discriminator)
/// A discriminator convention.
public static IDiscriminatorConvention LookupDiscriminatorConvention(Type type)
{
- BsonSerializer.ConfigLock.EnterReadLock();
- try
+ FastSingleton singleton;
+
+ if (!TryLookupDiscriminatorConvention(type, out singleton))
{
- IDiscriminatorConvention convention;
- if (__discriminatorConventions.TryGetValue(type, out convention))
- {
- return convention;
- }
+ var message = string.Format("No discriminator convention found for type {0}.", type.FullName);
+ throw new BsonSerializationException(message);
}
- finally
+
+ return singleton.Value;
+ }
+
+ ///
+ /// Looks up and populates the discriminator convention singleton for a type.
+ ///
+ /// The type.
+ /// The discriminator convention singleton for the type.
+ /// Whether a discriminator convention was returned for the Type.
+ private static bool TryLookupDiscriminatorConvention(
+ Type type,
+ out FastSingleton singleton)
+ {
+ singleton = FastSingleton.Lookup(type);
+ if (singleton.Value != null)
{
- BsonSerializer.ConfigLock.ExitReadLock();
+ return true;
}
BsonSerializer.ConfigLock.EnterWriteLock();
try
{
- IDiscriminatorConvention convention;
- if (!__discriminatorConventions.TryGetValue(type, out convention))
+ if (singleton.Value != null)
{
- // if there is no convention registered for object register the default one
- if (!__discriminatorConventions.ContainsKey(typeof(object)))
- {
- var defaultDiscriminatorConvention = StandardDiscriminatorConvention.Hierarchical;
- __discriminatorConventions.Add(typeof(object), defaultDiscriminatorConvention);
- if (type == typeof(object))
- {
- return defaultDiscriminatorConvention;
- }
- }
+ return true;
+ }
- if (type.IsInterface)
+ // if there is no convention registered for object register the default one
+ var objectSingleton = (FastSingleton)FastSingleton.Instance;
+ if (objectSingleton.Value == null)
+ {
+ var defaultDiscriminatorConvention = StandardDiscriminatorConvention.Hierarchical;
+ objectSingleton.TrySetValue(defaultDiscriminatorConvention, null);
+ if (type == typeof(object))
{
- // TODO: should convention for interfaces be inherited from parent interfaces?
- convention = __discriminatorConventions[typeof(object)];
- __discriminatorConventions[type] = convention;
+ singleton = objectSingleton;
+ return true;
}
- else
+ }
+
+ if (type.IsInterface)
+ {
+ // TODO: should convention for interfaces be inherited from parent interfaces?
+ singleton = FastSingleton.Lookup(type);
+ singleton.TrySetValue(objectSingleton.Value, null);
+ }
+ else
+ {
+ // inherit the discriminator convention from the closest parent that has one
+ Type parentType = type.BaseType;
+ for (;;)
{
- // inherit the discriminator convention from the closest parent that has one
- Type parentType = type.BaseType;
- while (convention == null)
+ if (parentType == null)
{
- if (parentType == null)
- {
- var message = string.Format("No discriminator convention found for type {0}.", type.FullName);
- throw new BsonSerializationException(message);
- }
- if (__discriminatorConventions.TryGetValue(parentType, out convention))
- {
- break;
- }
- parentType = parentType.BaseType;
+ singleton = null;
+ return false;
}
-
- // register this convention for all types between this and the parent type where we found the convention
- var unregisteredType = type;
- while (unregisteredType != parentType)
+ singleton = FastSingleton.Lookup(parentType);
+ if (singleton.Value != null)
{
- BsonDefaultSerializer.RegisterDiscriminatorConvention(unregisteredType, convention);
- unregisteredType = unregisteredType.BaseType;
+ break;
}
+ parentType = parentType.BaseType;
+ }
+
+ // register this convention for all types between this and the parent type where we found the convention
+ var unregisteredType = type;
+ while (unregisteredType != parentType)
+ {
+ BsonDefaultSerializer.RegisterDiscriminatorConvention(unregisteredType, singleton.Value);
+ unregisteredType = unregisteredType.BaseType;
}
}
- return convention;
+ return true;
}
finally
{
@@ -364,11 +380,8 @@ public static void RegisterDiscriminatorConvention(Type type, IDiscriminatorConv
BsonSerializer.ConfigLock.EnterWriteLock();
try
{
- if (!__discriminatorConventions.ContainsKey(type))
- {
- __discriminatorConventions.Add(type, convention);
- }
- else
+ var singleton = FastSingleton.Lookup(type);
+ if (!singleton.TrySetValue(convention, null))
{
var message = string.Format("There is already a discriminator convention registered for type {0}.", type.FullName);
throw new BsonSerializationException(message);
diff --git a/Bson/Serialization/BsonMemberMap.cs b/Bson/Serialization/BsonMemberMap.cs
index 3e4c12fc7da..27fd5765933 100755
--- a/Bson/Serialization/BsonMemberMap.cs
+++ b/Bson/Serialization/BsonMemberMap.cs
@@ -50,6 +50,8 @@ public class BsonMemberMap
private bool _ignoreIfDefault;
private bool _ignoreIfNull;
private object _defaultValue;
+ private readonly FastSingleton _discriminatorConvention;
+ private readonly FastSingleton _singletonSerializer;
// constructors
///
@@ -63,6 +65,8 @@ public BsonMemberMap(BsonClassMap classMap, MemberInfo memberInfo)
_memberInfo = memberInfo;
_memberType = BsonClassMap.GetMemberInfoType(memberInfo);
_defaultValue = GetDefaultValue(_memberType);
+ _discriminatorConvention = FastSingleton.Lookup(_memberType);
+ _singletonSerializer = FastSingleton.Lookup(_memberType);
}
// public properties
@@ -289,10 +293,34 @@ public IBsonSerializer GetSerializer(Type actualType)
{
return _serializer;
}
- else
+
+ if (actualType != _memberType)
{
return BsonSerializer.LookupSerializer(actualType);
}
+
+ if (_singletonSerializer.Value == null)
+ {
+ // LookupSerializer populates _singletonSerializer
+ BsonSerializer.LookupSerializer(_memberType);
+ }
+
+ return _singletonSerializer.Value;
+ }
+
+ ///
+ /// Gets the discriminator convention for the member type.
+ ///
+ /// The discriminator convention for the member type.
+ internal IDiscriminatorConvention GetDiscriminatorConvention()
+ {
+ if (_discriminatorConvention.Value == null)
+ {
+ // LookupDiscriminatorConvention will populate _discriminatorConvention
+ BsonDefaultSerializer.LookupDiscriminatorConvention(_memberType);
+ }
+
+ return _discriminatorConvention.Value;
}
///
diff --git a/Bson/Serialization/BsonSerializer.cs b/Bson/Serialization/BsonSerializer.cs
index 08393a1e4ff..bd4acb0ac5c 100644
--- a/Bson/Serialization/BsonSerializer.cs
+++ b/Bson/Serialization/BsonSerializer.cs
@@ -34,7 +34,6 @@ public static class BsonSerializer
// private static fields
private static ReaderWriterLockSlim __configLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
private static Dictionary __idGenerators = new Dictionary();
- private static Dictionary __serializers = new Dictionary();
private static Dictionary __genericSerializerDefinitions = new Dictionary();
private static List __serializationProviders = new List();
private static bool __useNullIdChecker = false;
@@ -43,7 +42,6 @@ public static class BsonSerializer
// static constructor
static BsonSerializer()
{
- RegisterDefaultSerializationProvider();
RegisterIdGenerators();
}
@@ -359,76 +357,21 @@ public static IIdGenerator LookupIdGenerator(Type type)
}
///
- /// Looks up a serializer for a Type.
+ /// Looks up and populates the serializer singleton for a type.
///
/// The Type.
/// A serializer for the Type.
public static IBsonSerializer LookupSerializer(Type type)
{
- __configLock.EnterReadLock();
- try
- {
- IBsonSerializer serializer;
- if (__serializers.TryGetValue(type, out serializer))
- {
- return serializer;
- }
- }
- finally
- {
- __configLock.ExitReadLock();
- }
+ FastSingleton singleton;
- __configLock.EnterWriteLock();
- try
+ if (!TryLookupSerializer(type, out singleton))
{
- IBsonSerializer serializer;
- if (!__serializers.TryGetValue(type, out serializer))
- {
- // special case for IBsonSerializable
- if (serializer == null && typeof(IBsonSerializable).IsAssignableFrom(type))
- {
- serializer = Serializers.BsonIBsonSerializableSerializer.Instance;
- }
-
- if (serializer == null && type.IsGenericType)
- {
- var genericTypeDefinition = type.GetGenericTypeDefinition();
- var genericSerializerDefinition = LookupGenericSerializerDefinition(genericTypeDefinition);
- if (genericSerializerDefinition != null)
- {
- var genericSerializerType = genericSerializerDefinition.MakeGenericType(type.GetGenericArguments());
- serializer = (IBsonSerializer)Activator.CreateInstance(genericSerializerType);
- }
- }
-
- if (serializer == null)
- {
- foreach (var serializationProvider in __serializationProviders)
- {
- serializer = serializationProvider.GetSerializer(type);
- if (serializer != null)
- {
- break;
- }
- }
- }
-
- if (serializer == null)
- {
- var message = string.Format("No serializer found for type {0}.", type.FullName);
- throw new BsonSerializationException(message);
- }
-
- __serializers[type] = serializer;
- }
-
- return serializer;
- }
- finally
- {
- __configLock.ExitWriteLock();
+ var message = string.Format("No serializer found for type {0}.", type.FullName);
+ throw new BsonSerializationException(message);
}
+
+ return singleton.Value;
}
///
@@ -475,6 +418,11 @@ public static void RegisterIdGenerator(Type type, IIdGenerator idGenerator)
/// The serialization provider.
public static void RegisterSerializationProvider(IBsonSerializationProvider provider)
{
+ if (provider == BsonDefaultSerializer.Instance)
+ {
+ throw new ArgumentException("BsonDefaultSerializer is implicitly registered", "provider");
+ }
+
__configLock.EnterWriteLock();
try
{
@@ -497,7 +445,12 @@ public static void RegisterSerializer(Type type, IBsonSerializer serializer)
__configLock.EnterWriteLock();
try
{
- __serializers[type] = serializer;
+ var singleton = FastSingleton.Lookup(type);
+ if (!singleton.TrySetValue(serializer, null))
+ {
+ var message = string.Format("There is already a serializer registered for type {0}.", type.FullName);
+ throw new BsonSerializationException(message);
+ }
}
finally
{
@@ -555,24 +508,93 @@ public static void Serialize(
object value,
IBsonSerializationOptions options)
{
- var bsonSerializable = value as IBsonSerializable;
- if (bsonSerializable != null)
- {
- bsonSerializable.Serialize(bsonWriter, nominalType, options);
- return;
- }
-
var actualType = (value == null) ? nominalType : value.GetType();
var serializer = LookupSerializer(actualType);
serializer.Serialize(bsonWriter, nominalType, value, options);
}
- // private static methods
- private static void RegisterDefaultSerializationProvider()
- {
- RegisterSerializationProvider(BsonDefaultSerializer.Instance);
+ ///
+ /// Looks up and populates the serializer singleton for a type.
+ ///
+ /// The Type.
+ /// The serializer singleton for the type.
+ /// Whether a serializer was returned for the Type.
+ internal static bool TryLookupSerializer(
+ Type type,
+ out FastSingleton singleton)
+ {
+ singleton = FastSingleton.Lookup(type);
+ if (singleton.Value != null)
+ {
+ return true;
+ }
+
+ __configLock.EnterWriteLock();
+ try
+ {
+ if (singleton.Value != null)
+ {
+ return true;
+ }
+
+ IBsonSerializer serializer;
+
+ if (__serializationProviders.Count > 0)
+ {
+ foreach (var serializationProvider in __serializationProviders)
+ {
+ serializer = serializationProvider.GetSerializer(type);
+ if (serializer != null)
+ {
+ singleton.TrySetValue(serializer, null);
+ return true;
+ }
+ }
+ }
+
+ if (typeof(IBsonSerializable).IsAssignableFrom(type))
+ {
+ serializer = Serializers.BsonIBsonSerializableSerializer.Instance;
+ if (serializer != null)
+ {
+ singleton.TrySetValue(serializer, null);
+ return true;
+ }
+ }
+
+ if (type.IsGenericType)
+ {
+ var genericTypeDefinition = type.GetGenericTypeDefinition();
+ var genericSerializerDefinition = LookupGenericSerializerDefinition(genericTypeDefinition);
+ if (genericSerializerDefinition != null)
+ {
+ var genericSerializerType = genericSerializerDefinition.MakeGenericType(type.GetGenericArguments());
+ serializer = (IBsonSerializer)Activator.CreateInstance(genericSerializerType);
+ if (serializer != null)
+ {
+ singleton.TrySetValue(serializer, null);
+ return true;
+ }
+ }
+ }
+
+ serializer = BsonDefaultSerializer.Instance.GetSerializer(type);
+ if (serializer != null)
+ {
+ singleton.TrySetValue(serializer, null);
+ return true;
+ }
+
+ serializer = null;
+ return false;
+ }
+ finally
+ {
+ __configLock.ExitWriteLock();
+ }
}
+ // private static methods
private static void RegisterIdGenerators()
{
BsonSerializer.RegisterIdGenerator(typeof(BsonObjectId), BsonObjectIdGenerator.Instance);
diff --git a/Bson/Serialization/Serializers/ImageSerializers.cs b/Bson/Serialization/Serializers/ImageSerializers.cs
index 8b76f6e2e0e..141f1c56507 100644
--- a/Bson/Serialization/Serializers/ImageSerializers.cs
+++ b/Bson/Serialization/Serializers/ImageSerializers.cs
@@ -24,6 +24,7 @@
using MongoDB.Bson.IO;
using MongoDB.Bson.Serialization;
+using MongoDB.Bson.Serialization.Conventions;
namespace MongoDB.Bson.Serialization.Serializers
{
@@ -71,7 +72,12 @@ public override object Deserialize(
throw new ArgumentException(message, "nominalType");
}
- var discriminatorConvention = BsonDefaultSerializer.LookupDiscriminatorConvention(typeof(Image));
+ var discriminatorConvention = FastSingleton.Instance.Value;
+ if (discriminatorConvention == null)
+ {
+ // LookupDiscriminatorConvention populates FastSingleton
+ discriminatorConvention = BsonDefaultSerializer.LookupDiscriminatorConvention(typeof(Image));
+ }
var actualType = discriminatorConvention.GetActualType(bsonReader, typeof(Image));
if (actualType == typeof(Image))
{
diff --git a/Bson/Serialization/Serializers/ObjectSerializer.cs b/Bson/Serialization/Serializers/ObjectSerializer.cs
index 382c845117a..cfef8afacd1 100644
--- a/Bson/Serialization/Serializers/ObjectSerializer.cs
+++ b/Bson/Serialization/Serializers/ObjectSerializer.cs
@@ -22,6 +22,7 @@
using MongoDB.Bson.IO;
using MongoDB.Bson.Serialization;
+using MongoDB.Bson.Serialization.Conventions;
namespace MongoDB.Bson.Serialization.Serializers
{
@@ -87,7 +88,12 @@ public object Deserialize(BsonReader bsonReader, Type nominalType, IBsonSerializ
}
}
- var discriminatorConvention = BsonDefaultSerializer.LookupDiscriminatorConvention(typeof(object));
+ var discriminatorConvention = FastSingleton.Instance.Value;
+ if (discriminatorConvention == null)
+ {
+ // LookupDiscriminatorConvention populates FastSingleton
+ discriminatorConvention = BsonDefaultSerializer.LookupDiscriminatorConvention(typeof(object));
+ }
var actualType = discriminatorConvention.GetActualType(bsonReader, typeof(object));
if (actualType == typeof(object))
{