@@ -33,6 +33,7 @@ namespace SIL.LCModel.Infrastructure.Impl
3333 internal sealed class CmObjectSurrogate : ICmObjectSurrogate //, IEquatable<CmObjectSurrogate>
3434 {
3535 private static Dictionary < string , ConstructorInfo > s_classToConstructorInfo ;
36+ private static readonly object s_constructorLock = new object ( ) ;
3637 /// <summary>
3738 /// It's common that hundreds of thousands of surrogates only use a few hundred class names. This is a local interning
3839 /// of those names.
@@ -227,14 +228,22 @@ internal static void InitializeConstructors(List<Type> cmObjectTypes)
227228 {
228229 if ( s_classToConstructorInfo != null ) return ;
229230
230- s_classToConstructorInfo = new Dictionary < string , ConstructorInfo > ( ) ;
231- // Get default constructor.
232- // Only do this once, since they are stored in a static data member.
233- foreach ( var lcmType in cmObjectTypes )
231+ lock ( s_constructorLock )
234232 {
235- if ( lcmType . IsAbstract ) continue ;
233+ if ( s_classToConstructorInfo != null ) return ;
236234
237- s_classToConstructorInfo . Add ( lcmType . Name , lcmType . GetConstructor ( BindingFlags . Instance | BindingFlags . Public | BindingFlags . NonPublic , null , Type . EmptyTypes , null ) ) ;
235+ var dict = new Dictionary < string , ConstructorInfo > ( ) ;
236+ // Get default constructor.
237+ // Only do this once, since they are stored in a static data member.
238+ foreach ( var lcmType in cmObjectTypes )
239+ {
240+ if ( lcmType . IsAbstract ) continue ;
241+
242+ dict . Add ( lcmType . Name , lcmType . GetConstructor ( BindingFlags . Instance | BindingFlags . Public | BindingFlags . NonPublic , null , Type . EmptyTypes , null ) ) ;
243+ }
244+
245+ // Assign only after fully populated so the outer null check never sees a partial dictionary
246+ s_classToConstructorInfo = dict ;
238247 }
239248 }
240249
0 commit comments