14
14
*/
15
15
16
16
using System ;
17
+ using System . Collections . Concurrent ;
17
18
using System . Collections . Generic ;
18
19
using System . IO ;
19
20
using System . Linq ;
@@ -41,7 +42,8 @@ public static class BsonSerializer
41
42
private static HashSet < Type > __discriminatedTypes = new HashSet < Type > ( ) ;
42
43
private static BsonSerializerRegistry __serializerRegistry ;
43
44
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 > ( ) ;
45
47
46
48
private static bool __useNullIdChecker = false ;
47
49
private static bool __useZeroIdChecker = false ;
@@ -679,23 +681,15 @@ public static void Serialize(
679
681
// internal static methods
680
682
internal static void EnsureKnownTypesAreRegistered ( Type nominalType )
681
683
{
682
- __configLock . EnterReadLock ( ) ;
683
- try
684
- {
685
- if ( __typesWithRegisteredKnownTypes . Contains ( nominalType ) )
686
- {
687
- return ;
688
- }
689
- }
690
- finally
684
+ if ( __typesWithRegisteredKnownTypes . ContainsKey ( nominalType ) )
691
685
{
692
- __configLock . ExitReadLock ( ) ;
686
+ return ;
693
687
}
694
688
695
689
__configLock . EnterWriteLock ( ) ;
696
690
try
697
691
{
698
- if ( ! __typesWithRegisteredKnownTypes . Contains ( nominalType ) )
692
+ if ( ! __typesWithRegisteredKnownTypes . ContainsKey ( nominalType ) )
699
693
{
700
694
// only call LookupClassMap for classes with a BsonKnownTypesAttribute
701
695
#if NET452
@@ -709,7 +703,10 @@ internal static void EnsureKnownTypesAreRegistered(Type nominalType)
709
703
LookupSerializer ( nominalType ) ;
710
704
}
711
705
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 ;
713
710
}
714
711
}
715
712
finally
0 commit comments