From f6533e1d3838b636a63783e1fec6c958714137b6 Mon Sep 17 00:00:00 2001 From: WinCPP Date: Wed, 1 Mar 2017 08:49:49 +0530 Subject: [PATCH] Corefx #16274 - LazyInitializer.EnsureInitialized overload for reference types LazyInitializer.EnsureInitialized overload for reference types that does not take boolean for tracking initialization status of the reference type object. Null check on the object parameter is sufficient to whether or not it has been initialized. --- .../src/System/Threading/LazyInitializer.cs | 91 ++++++++++++------- 1 file changed, 57 insertions(+), 34 deletions(-) diff --git a/src/mscorlib/src/System/Threading/LazyInitializer.cs b/src/mscorlib/src/System/Threading/LazyInitializer.cs index 82fb2579bbed..6c84caa5a6dd 100644 --- a/src/mscorlib/src/System/Threading/LazyInitializer.cs +++ b/src/mscorlib/src/System/Threading/LazyInitializer.cs @@ -82,16 +82,8 @@ public static class LazyInitializer /// if an object was not used and to then dispose of the object appropriately. /// /// - public static T EnsureInitialized(ref T target) where T : class - { - // Fast path. - if (Volatile.Read(ref target) != null) - { - return target; - } - - return EnsureInitializedCore(ref target, LazyHelpers.s_activatorFactorySelector); - } + public static T EnsureInitialized(ref T target) where T : class => + Volatile.Read(ref target) ?? EnsureInitializedCore(ref target, LazyHelpers.s_activatorFactorySelector); /// /// Initializes a target reference type using the specified function if it has not already been @@ -121,16 +113,8 @@ public static T EnsureInitialized(ref T target) where T : class /// if an object was not used and to then dispose of the object appropriately. /// /// - public static T EnsureInitialized(ref T target, Func valueFactory) where T : class - { - // Fast path. - if (Volatile.Read(ref target) != null) - { - return target; - } - - return EnsureInitializedCore(ref target, valueFactory); - } + public static T EnsureInitialized(ref T target, Func valueFactory) where T : class => + Volatile.Read(ref target) ?? EnsureInitializedCore(ref target, valueFactory); /// /// Initialize the target using the given delegate (slow path). @@ -152,7 +136,6 @@ private static T EnsureInitializedCore(ref T target, Func valueFactory) wh return target; } - /// /// Initializes a target reference or value type with its default constructor if it has not already /// been initialized. @@ -198,10 +181,32 @@ public static T EnsureInitialized(ref T target, ref bool initialized, ref obj return target; } - return EnsureInitializedCore(ref target, ref initialized, ref syncLock, valueFactory); } + /// + /// Ensure the lock object is intialized. + /// + /// A reference to a location containing a mutual exclusive lock. If is null, + /// a new object will be instantiated. + /// Initialized lock object. + private static object EnsureLockInitialized(ref object syncLock) => + syncLock ?? + Interlocked.CompareExchange(ref syncLock, new object(), null) ?? + syncLock; + + /// + /// Initializes a target reference type with a specified function if it has not already been initialized. + /// + /// The type of the reference to be initialized. Has to be reference type. + /// A reference of type to initialize if it has not already been initialized. + /// A reference to an object used as the mutually exclusive lock for initializing + /// . If is null, a new object will be instantiated. + /// The invoked to initialize the reference. + /// The initialized value of type . + public static T EnsureInitialized(ref T target, ref object syncLock, Func valueFactory) where T : class => + Volatile.Read(ref target) ?? EnsureInitializedCore(ref target, ref syncLock, valueFactory); + /// /// Ensure the target is initialized and return the value (slow path). This overload permits nulls /// and also works for value type targets. Uses the supplied function to create the value. @@ -217,25 +222,43 @@ public static T EnsureInitialized(ref T target, ref bool initialized, ref obj /// The initialized object. private static T EnsureInitializedCore(ref T target, ref bool initialized, ref object syncLock, Func valueFactory) { - // Lazily initialize the lock if necessary. - object slock = syncLock; - if (slock == null) + // Lazily initialize the lock if necessary and, then double check if initialization is still required. + lock (EnsureLockInitialized(ref syncLock)) { - object newLock = new object(); - slock = Interlocked.CompareExchange(ref syncLock, newLock, null); - if (slock == null) + if (!Volatile.Read(ref initialized)) { - slock = newLock; + target = valueFactory(); + Volatile.Write(ref initialized, true); } } - // Now double check that initialization is still required. - lock (slock) + return target; + } + + /// + /// Ensure the target is initialized and return the value (slow path). This overload works only for reference type targets. + /// Uses the supplied function to create the value. + /// + /// The type of target. Has to be reference type. + /// A reference to the target to be initialized. + /// A reference to a location containing a mutual exclusive lock. If is null, + /// a new object will be instantiated. + /// + /// The to invoke in order to produce the lazily-initialized value. + /// + /// The initialized object. + private static T EnsureInitializedCore(ref T target, ref object syncLock, Func valueFactory) where T : class + { + // Lazily initialize the lock if necessary and, then double check if initialization is still required. + lock (EnsureLockInitialized(ref syncLock)) { - if (!Volatile.Read(ref initialized)) + if (Volatile.Read(ref target) == null) { - target = valueFactory(); - Volatile.Write(ref initialized, true); + Volatile.Write(ref target, valueFactory()); + if (target == null) + { + throw new InvalidOperationException(Environment.GetResourceString("Lazy_StaticInit_InvalidOperation")); + } } }