@@ -31,11 +31,6 @@ namespace MongoDB.Bson.Serialization
3131 /// </summary>
3232 public class BsonClassMap
3333 {
34- // private static fields
35- private readonly static Dictionary < Type , BsonClassMap > __classMaps = new Dictionary < Type , BsonClassMap > ( ) ;
36- private readonly static Queue < Type > __knownTypesQueue = new Queue < Type > ( ) ;
37- private static int __freezeNestingLevel = 0 ;
38-
3934 // private fields
4035 private readonly Type _classType ;
4136 private readonly List < BsonCreatorMap > _creatorMaps ;
@@ -282,103 +277,32 @@ public static Type GetMemberInfoType(MemberInfo memberInfo)
282277 /// Gets all registered class maps.
283278 /// </summary>
284279 /// <returns>All registered class maps.</returns>
285- public static IEnumerable < BsonClassMap > GetRegisteredClassMaps ( )
286- {
287- BsonSerializer . ConfigLock . EnterReadLock ( ) ; //TODO It would make sense to look at this after the PR by Robert is merged
288- try
289- {
290- return __classMaps . Values . ToList ( ) ; // return a copy for thread safety
291- }
292- finally
293- {
294- BsonSerializer . ConfigLock . ExitReadLock ( ) ;
295- }
296- }
280+ public static IEnumerable < BsonClassMap > GetRegisteredClassMaps ( ) =>
281+ BsonSerializer . DefaultDomain . ClassMapDomain . GetRegisteredClassMaps ( ) ;
297282
298283 /// <summary>
299284 /// Checks whether a class map is registered for a type.
300285 /// </summary>
301286 /// <param name="type">The type to check.</param>
302287 /// <returns>True if there is a class map registered for the type.</returns>
303- public static bool IsClassMapRegistered ( Type type )
304- {
305- if ( type == null )
306- {
307- throw new ArgumentNullException ( "type" ) ;
308- }
309-
310- BsonSerializer . ConfigLock . EnterReadLock ( ) ;
311- try
312- {
313- return __classMaps . ContainsKey ( type ) ;
314- }
315- finally
316- {
317- BsonSerializer . ConfigLock . ExitReadLock ( ) ;
318- }
319- }
288+ public static bool IsClassMapRegistered ( Type type ) =>
289+ BsonSerializer . DefaultDomain . ClassMapDomain . IsClassMapRegistered ( type ) ;
320290
321291 /// <summary>
322292 /// Looks up a class map (will AutoMap the class if no class map is registered).
323293 /// </summary>
324294 /// <param name="classType">The class type.</param>
325295 /// <returns>The class map.</returns>
326- public static BsonClassMap LookupClassMap ( Type classType )
327- {
328- if ( classType == null )
329- {
330- throw new ArgumentNullException ( "classType" ) ;
331- }
332-
333- BsonSerializer . ConfigLock . EnterReadLock ( ) ;
334- try
335- {
336- if ( __classMaps . TryGetValue ( classType , out var classMap ) )
337- {
338- if ( classMap . IsFrozen )
339- {
340- return classMap ;
341- }
342- }
343- }
344- finally
345- {
346- BsonSerializer . ConfigLock . ExitReadLock ( ) ;
347- }
348-
349- // automatically create a new classMap for classType and register it (unless another thread does first)
350- // do the work of speculatively creating a new class map outside of holding any lock
351- var classMapDefinition = typeof ( BsonClassMap < > ) ;
352- var classMapType = classMapDefinition . MakeGenericType ( classType ) ;
353- var newClassMap = ( BsonClassMap ) Activator . CreateInstance ( classMapType ) ;
354- newClassMap . AutoMap ( ) ;
355-
356- BsonSerializer . ConfigLock . EnterWriteLock ( ) ;
357- try
358- {
359- if ( ! __classMaps . TryGetValue ( classType , out var classMap ) )
360- {
361- RegisterClassMap ( newClassMap ) ;
362- classMap = newClassMap ;
363- }
364-
365- return classMap . Freeze ( ) ;
366- }
367- finally
368- {
369- BsonSerializer . ConfigLock . ExitWriteLock ( ) ;
370- }
371- }
296+ public static BsonClassMap LookupClassMap ( Type classType ) =>
297+ BsonSerializer . DefaultDomain . ClassMapDomain . LookupClassMap ( classType ) ;
372298
373299 /// <summary>
374300 /// Creates and registers a class map.
375301 /// </summary>
376302 /// <typeparam name="TClass">The class.</typeparam>
377303 /// <returns>The class map.</returns>
378- public static BsonClassMap < TClass > RegisterClassMap < TClass > ( ) //TODO We should move the static methods here to IBSonSerializerDomain
379- {
380- return RegisterClassMap < TClass > ( cm => { cm . AutoMap ( ) ; } ) ;
381- }
304+ public static BsonClassMap < TClass > RegisterClassMap < TClass > ( ) =>
305+ BsonSerializer . DefaultDomain . ClassMapDomain . RegisterClassMap < TClass > ( ) ;
382306
383307 /// <summary>
384308 /// Creates and registers a class map.
@@ -387,52 +311,22 @@ public static BsonClassMap<TClass> RegisterClassMap<TClass>() //TODO We should
387311 /// <param name="classMapInitializer">The class map initializer.</param>
388312 /// <returns>The class map.</returns>
389313 public static BsonClassMap < TClass > RegisterClassMap < TClass > ( Action < BsonClassMap < TClass > > classMapInitializer )
390- {
391- var classMap = new BsonClassMap < TClass > ( classMapInitializer ) ;
392- RegisterClassMap ( classMap ) ;
393- return classMap ;
394- }
314+ => BsonSerializer . DefaultDomain . ClassMapDomain . RegisterClassMap ( classMapInitializer ) ;
395315
396316 /// <summary>
397317 /// Registers a class map.
398318 /// </summary>
399319 /// <param name="classMap">The class map.</param>
400320 public static void RegisterClassMap ( BsonClassMap classMap )
401- {
402- if ( classMap == null )
403- {
404- throw new ArgumentNullException ( "classMap" ) ;
405- }
406-
407- BsonSerializer . ConfigLock . EnterWriteLock ( ) ;
408- try
409- {
410- // note: class maps can NOT be replaced (because derived classes refer to existing instance)
411- __classMaps . Add ( classMap . ClassType , classMap ) ;
412- BsonSerializer . RegisterDiscriminator ( classMap . ClassType , classMap . Discriminator ) ;
413- }
414- finally
415- {
416- BsonSerializer . ConfigLock . ExitWriteLock ( ) ;
417- }
418- }
321+ => BsonSerializer . DefaultDomain . ClassMapDomain . RegisterClassMap ( classMap ) ;
419322
420323 /// <summary>
421324 /// Registers a class map if it is not already registered.
422325 /// </summary>
423326 /// <typeparam name="TClass">The class.</typeparam>
424327 /// <returns>True if this call registered the class map, false if the class map was already registered.</returns>
425328 public static bool TryRegisterClassMap < TClass > ( )
426- {
427- return TryRegisterClassMap ( ClassMapFactory ) ;
428-
429- static BsonClassMap < TClass > ClassMapFactory ( )
430- {
431- var classMap = new BsonClassMap < TClass > ( ) ;
432- classMap . AutoMap ( ) ;
433- return classMap ;
434- }
435- }
329+ => BsonSerializer . DefaultDomain . ClassMapDomain . TryRegisterClassMap < TClass > ( ) ;
436330
437331 /// <summary>
438332 /// Registers a class map if it is not already registered.
@@ -441,19 +335,7 @@ static BsonClassMap<TClass> ClassMapFactory()
441335 /// <param name="classMap">The class map.</param>
442336 /// <returns>True if this call registered the class map, false if the class map was already registered.</returns>
443337 public static bool TryRegisterClassMap < TClass > ( BsonClassMap < TClass > classMap )
444- {
445- if ( classMap == null )
446- {
447- throw new ArgumentNullException ( nameof ( classMap ) ) ;
448- }
449-
450- return TryRegisterClassMap ( ClassMapFactory ) ;
451-
452- BsonClassMap < TClass > ClassMapFactory ( )
453- {
454- return classMap ;
455- }
456- }
338+ => BsonSerializer . DefaultDomain . ClassMapDomain . TryRegisterClassMap ( classMap ) ;
457339
458340 /// <summary>
459341 /// Registers a class map if it is not already registered.
@@ -462,19 +344,7 @@ BsonClassMap<TClass> ClassMapFactory()
462344 /// <param name="classMapInitializer">The class map initializer (only called if the class map is not already registered).</param>
463345 /// <returns>True if this call registered the class map, false if the class map was already registered.</returns>
464346 public static bool TryRegisterClassMap < TClass > ( Action < BsonClassMap < TClass > > classMapInitializer )
465- {
466- if ( classMapInitializer == null )
467- {
468- throw new ArgumentNullException ( nameof ( classMapInitializer ) ) ;
469- }
470-
471- return TryRegisterClassMap ( ClassMapFactory ) ;
472-
473- BsonClassMap < TClass > ClassMapFactory ( )
474- {
475- return new BsonClassMap < TClass > ( classMapInitializer ) ;
476- }
477- }
347+ => BsonSerializer . DefaultDomain . ClassMapDomain . TryRegisterClassMap ( classMapInitializer ) ;
478348
479349 /// <summary>
480350 /// Registers a class map if it is not already registered.
@@ -483,45 +353,7 @@ BsonClassMap<TClass> ClassMapFactory()
483353 /// <param name="classMapFactory">The class map factory (only called if the class map is not already registered).</param>
484354 /// <returns>True if this call registered the class map, false if the class map was already registered.</returns>
485355 public static bool TryRegisterClassMap < TClass > ( Func < BsonClassMap < TClass > > classMapFactory )
486- {
487- if ( classMapFactory == null )
488- {
489- throw new ArgumentNullException ( nameof ( classMapFactory ) ) ;
490- }
491-
492- BsonSerializer . ConfigLock . EnterReadLock ( ) ;
493- try
494- {
495- if ( __classMaps . ContainsKey ( typeof ( TClass ) ) )
496- {
497- return false ;
498- }
499- }
500- finally
501- {
502- BsonSerializer . ConfigLock . ExitReadLock ( ) ;
503- }
504-
505- BsonSerializer . ConfigLock . EnterWriteLock ( ) ;
506- try
507- {
508- if ( __classMaps . ContainsKey ( typeof ( TClass ) ) )
509- {
510- return false ;
511- }
512- else
513- {
514- // create a classMap for TClass and register it
515- var classMap = classMapFactory ( ) ;
516- RegisterClassMap ( classMap ) ;
517- return true ;
518- }
519- }
520- finally
521- {
522- BsonSerializer . ConfigLock . ExitWriteLock ( ) ;
523- }
524- }
356+ => BsonSerializer . DefaultDomain . ClassMapDomain . TryRegisterClassMap ( classMapFactory ) ;
525357
526358 // public methods
527359 /// <summary>
@@ -573,13 +405,30 @@ obj is BsonClassMap other &&
573405 /// <inheritdoc/>
574406 public override int GetHashCode ( ) => 0 ;
575407
408+ internal class FreezeContext
409+ {
410+ public int FreezeNestingLevel { get ; set ; } = 0 ;
411+ public Queue < Type > KnownTypesQueue { get ; set ; } = new ( ) ;
412+ public IBsonSerializationDomain SerializationDomain { get ; set ; }
413+ }
414+
576415 /// <summary>
577416 /// Freezes the class map.
578417 /// </summary>
579418 /// <returns>The frozen class map.</returns>
580- public BsonClassMap Freeze ( )
419+ public BsonClassMap Freeze ( ) => Freeze ( BsonSerializer . DefaultDomain ) ;
420+
421+
422+ internal BsonClassMap Freeze ( IBsonSerializationDomain domain )
423+ {
424+ var freezeContext = new FreezeContext ( ) { SerializationDomain = domain } ;
425+ return Freeze ( freezeContext ) ;
426+ }
427+
428+ private BsonClassMap Freeze ( FreezeContext context )
581429 {
582- BsonSerializer . ConfigLock . EnterReadLock ( ) ;
430+ var configLock = ( context . SerializationDomain as IBsonSerializationDomainInternal ) ! . ConfigLock ;
431+ configLock . EnterReadLock ( ) ;
583432 try
584433 {
585434 if ( _frozen )
@@ -589,15 +438,15 @@ public BsonClassMap Freeze()
589438 }
590439 finally
591440 {
592- BsonSerializer . ConfigLock . ExitReadLock ( ) ;
441+ configLock . ExitReadLock ( ) ;
593442 }
594443
595- BsonSerializer . ConfigLock . EnterWriteLock ( ) ;
444+ configLock . EnterWriteLock ( ) ;
596445 try
597446 {
598447 if ( ! _frozen )
599448 {
600- __freezeNestingLevel ++ ;
449+ context . FreezeNestingLevel ++ ;
601450 try
602451 {
603452 var baseType = _classType . GetTypeInfo ( ) . BaseType ;
@@ -607,7 +456,7 @@ public BsonClassMap Freeze()
607456 {
608457 _baseClassMap = LookupClassMap ( baseType ) ;
609458 }
610- _baseClassMap . Freeze ( ) ;
459+ _baseClassMap . Freeze ( context ) ; //TODO This is not necessary, because LookupClassMap will only return a frozen class map
611460 _discriminatorIsRequired |= _baseClassMap . _discriminatorIsRequired ;
612461 _hasRootClass |= ( _isRootClass || _baseClassMap . HasRootClass ) ;
613462 _allMemberMaps . AddRange ( _baseClassMap . AllMemberMaps ) ;
@@ -699,28 +548,28 @@ public BsonClassMap Freeze()
699548 // this avoids infinite recursion when going back down the inheritance tree while processing known types
700549 foreach ( var knownType in _knownTypes )
701550 {
702- __knownTypesQueue . Enqueue ( knownType ) ;
551+ context . KnownTypesQueue . Enqueue ( knownType ) ;
703552 }
704553
705554 // if we are back to the first level go ahead and process any queued known types
706- if ( __freezeNestingLevel == 1 )
555+ if ( context . FreezeNestingLevel == 1 )
707556 {
708- while ( __knownTypesQueue . Count != 0 )
557+ while ( context . KnownTypesQueue . Count != 0 )
709558 {
710- var knownType = __knownTypesQueue . Dequeue ( ) ;
559+ var knownType = context . KnownTypesQueue . Dequeue ( ) ;
711560 LookupClassMap ( knownType ) ; // will AutoMap and/or Freeze knownType if necessary
712561 }
713562 }
714563 }
715564 finally
716565 {
717- __freezeNestingLevel -- ;
566+ context . FreezeNestingLevel -- ;
718567 }
719568 }
720569 }
721570 finally
722571 {
723- BsonSerializer . ConfigLock . ExitWriteLock ( ) ;
572+ configLock . ExitWriteLock ( ) ;
724573 }
725574 return this ;
726575 }
0 commit comments