1414*/
1515
1616using System ;
17+ using System . Collections . Concurrent ;
1718using System . Collections . Generic ;
1819using System . IO ;
1920using System . Linq ;
@@ -41,7 +42,8 @@ public static class BsonSerializer
4142 private static HashSet < Type > __discriminatedTypes = new HashSet < Type > ( ) ;
4243 private static BsonSerializerRegistry __serializerRegistry ;
4344 private static TypeMappingSerializationProvider __typeMappingSerializationProvider ;
44- private static HashSet < Type > __typesWithRegisteredKnownTypes = new HashSet < Type > ( ) ;
45+ // ConcurrentDictionary<Type, object> is being used as a concurrent set of Type. The values will always be null.
46+ private static ConcurrentDictionary < Type , object > __typesWithRegisteredKnownTypes = new ConcurrentDictionary < Type , object > ( ) ;
4547
4648 private static bool __useNullIdChecker = false ;
4749 private static bool __useZeroIdChecker = false ;
@@ -679,23 +681,15 @@ public static void Serialize(
679681 // internal static methods
680682 internal static void EnsureKnownTypesAreRegistered ( Type nominalType )
681683 {
682- __configLock . EnterReadLock ( ) ;
683- try
684- {
685- if ( __typesWithRegisteredKnownTypes . Contains ( nominalType ) )
686- {
687- return ;
688- }
689- }
690- finally
684+ if ( __typesWithRegisteredKnownTypes . ContainsKey ( nominalType ) )
691685 {
692- __configLock . ExitReadLock ( ) ;
686+ return ;
693687 }
694688
695689 __configLock . EnterWriteLock ( ) ;
696690 try
697691 {
698- if ( ! __typesWithRegisteredKnownTypes . Contains ( nominalType ) )
692+ if ( ! __typesWithRegisteredKnownTypes . ContainsKey ( nominalType ) )
699693 {
700694 // only call LookupClassMap for classes with a BsonKnownTypesAttribute
701695#if NET452
@@ -709,7 +703,10 @@ internal static void EnsureKnownTypesAreRegistered(Type nominalType)
709703 LookupSerializer ( nominalType ) ;
710704 }
711705
712- __typesWithRegisteredKnownTypes . Add ( nominalType ) ;
706+ // NOTE: The nominalType MUST be added to __typesWithRegisteredKnownTypes after all registration
707+ // work is done to ensure that other threads don't access a partially registered nominalType
708+ // when performing the initial check above outside the __config lock.
709+ __typesWithRegisteredKnownTypes [ nominalType ] = null ;
713710 }
714711 }
715712 finally
0 commit comments