// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
//
// LazyInitializer.cs
//
// [....]
//
// a set of lightweight static helpers for lazy initialization.
//
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
using System.Security.Permissions;
using System.Diagnostics.Contracts;
namespace System.Threading
{
///
/// Specifies how a instance should synchronize access among multiple threads.
///
public enum LazyThreadSafetyMode
{
///
/// This mode makes no guarantees around the thread-safety of the instance. If used from multiple threads, the behavior of the is undefined.
/// This mode should be used when a is guaranteed to never be initialized from more than one thread simultaneously and high performance is crucial.
/// If valueFactory throws an exception when the is initialized, the exception will be cached and returned on subsequent accesses to Value. Also, if valueFactory recursively
/// accesses Value on this instance, a will be thrown.
///
None,
///
/// When multiple threads attempt to simultaneously initialize a instance, this mode allows each thread to execute the
/// valueFactory but only the first thread to complete initialization will be allowed to set the final value of the .
/// Once initialized successfully, any future calls to Value will return the cached result. If valueFactory throws an exception on any thread, that exception will be
/// propagated out of Value. If any thread executes valueFactory without throwing an exception and, therefore, successfully sets the value, that value will be returned on
/// subsequent accesses to Value from any thread. If no thread succeeds in setting the value, IsValueCreated will remain false and subsequent accesses to Value will result in
/// the valueFactory delegate re-executing. Also, if valueFactory recursively accesses Value on this instance, an exception will NOT be thrown.
///
PublicationOnly,
///
/// This mode uses locks to ensure that only a single thread can initialize a instance in a thread-safe manner. In general,
/// taken if this mode is used in conjunction with a valueFactory delegate that uses locks internally, a deadlock can occur if not
/// handled carefully. If valueFactory throws an exception when the is initialized, the exception will be cached and returned on
/// subsequent accesses to Value. Also, if valueFactory recursively accesses Value on this instance, a will be thrown.
///
ExecutionAndPublication
}
///
/// Provides lazy initialization routines.
///
///
/// These routines avoid needing to allocate a dedicated, lazy-initialization instance, instead using
/// references to ensure targets have been initialized as they are accessed.
///
[HostProtection(Synchronization = true, ExternalThreading = true)]
public static class LazyInitializer
{
///
/// Initializes a target reference type with the type's default constructor if the target has not
/// already been initialized.
///
/// The refence type of the reference to be initialized.
/// A reference of type to initialize if it has not
/// already been initialized.
/// The initialized reference of type .
/// Type does not have a default
/// constructor.
///
/// Permissions to access the constructor of type were missing.
///
///
///
/// This method may only be used on reference types. To ensure initialization of value
/// types, see other overloads of EnsureInitialized.
///
///
/// This method may be used concurrently by multiple threads to initialize .
/// In the event that multiple threads access this method concurrently, multiple instances of
/// may be created, but only one will be stored into . In such an occurrence, this method will not dispose of the
/// objects that were not stored. If such objects must be disposed, it is up to the caller to determine
/// 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);
}
///
/// Initializes a target reference type using the specified function if it has not already been
/// initialized.
///
/// The reference type of the reference to be initialized.
/// The reference of type to initialize if it has not
/// already been initialized.
/// The invoked to initialize the
/// reference.
/// The initialized reference of type .
/// Type does not have a
/// default constructor.
/// returned
/// null.
///
///
/// This method may only be used on reference types, and may
/// not return a null reference (Nothing in Visual Basic). To ensure initialization of value types or
/// to allow null reference types, see other overloads of EnsureInitialized.
///
///
/// This method may be used concurrently by multiple threads to initialize .
/// In the event that multiple threads access this method concurrently, multiple instances of
/// may be created, but only one will be stored into . In such an occurrence, this method will not dispose of the
/// objects that were not stored. If such objects must be disposed, it is up to the caller to determine
/// 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);
}
///
/// Initialize the target using the given delegate (slow path).
///
/// The reference type of the reference to be initialized.
/// The variable that need to be initialized
/// The delegate that will be executed to initialize the target
/// The initialized variable
private static T EnsureInitializedCore(ref T target, Func valueFactory) where T : class
{
T value = valueFactory();
if (value == null)
{
throw new InvalidOperationException(Environment.GetResourceString("Lazy_StaticInit_InvalidOperation"));
}
Interlocked.CompareExchange(ref target, value, null);
Contract.Assert(target != null);
return target;
}
///
/// Initializes a target reference or value type with its default constructor if it has not already
/// been initialized.
///
/// The type of the reference to be initialized.
/// A reference or value of type to initialize if it
/// has not already been initialized.
/// A reference to a boolean that determines whether the target has 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 initialized value of type .
public static T EnsureInitialized(ref T target, ref bool initialized, ref object syncLock)
{
// Fast path.
if (Volatile.Read(ref initialized))
{
return target;
}
return EnsureInitializedCore(ref target, ref initialized, ref syncLock, LazyHelpers.s_activatorFactorySelector);
}
///
/// Initializes a target reference or value type with a specified function if it has not already been
/// initialized.
///
/// The type of the reference to be initialized.
/// A reference or value of type to initialize if it
/// has not already been initialized.
/// A reference to a boolean that determines whether the target has 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 or value.
/// The initialized value of type .
public static T EnsureInitialized(ref T target, ref bool initialized, ref object syncLock, Func valueFactory)
{
// Fast path.
if (Volatile.Read(ref initialized))
{
return target;
}
return EnsureInitializedCore(ref target, ref initialized, 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.
///
/// The type of target.
/// A reference to the target to be initialized.
/// A reference to a location tracking whether the target has been 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 bool initialized, ref object syncLock, Func valueFactory)
{
// Lazily initialize the lock if necessary.
object slock = syncLock;
if (slock == null)
{
object newLock = new object();
slock = Interlocked.CompareExchange(ref syncLock, newLock, null);
if (slock == null)
{
slock = newLock;
}
}
// Now double check that initialization is still required.
lock (slock)
{
if (!Volatile.Read(ref initialized))
{
target = valueFactory();
Volatile.Write(ref initialized, true);
}
}
return target;
}
}
// Caches the activation selector function to avoid delegate allocations.
static class LazyHelpers
{
internal static Func s_activatorFactorySelector = new Func(ActivatorFactorySelector);
private static T ActivatorFactorySelector()
{
try
{
return (T)Activator.CreateInstance(typeof(T));
}
catch (MissingMethodException)
{
throw new MissingMemberException(Environment.GetResourceString("Lazy_CreateValue_NoParameterlessCtorForT"));
}
}
}
}