Lazy.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / clr / src / BCL / System / Lazy.cs / 1305376 / Lazy.cs

                            #pragma warning disable 0420 
// ==++==
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ==--==
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 
// 
// Lazy.cs
// 
// [....]
//
// A class that provides a simple, lightweight implementation of lazy initialization,
// obviating the need for a developer to implement a custom, thread-safe lazy initialization 
// solution.
// 
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 

using System.Runtime; 
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Diagnostics; 
using System.Runtime.Serialization;
using System.Threading; 
using System.Diagnostics.Contracts; 

namespace System 
{

    /// 
    /// Provides support for lazy initialization. 
    /// 
    /// Specifies the type of element being laziliy initialized. 
    ///  
    /// 
    /// By default, all public and protected members of  are thread-safe and may be used 
    /// concurrently from multiple threads.  These thread-safety guarantees may be removed optionally and per instance
    /// using parameters to the type's constructors.
    /// 
    ///  
    [Serializable]
    [ComVisible(false)] 
    [HostProtection(Synchronization = true, ExternalThreading = true)] 
    [DebuggerTypeProxy(typeof(System_LazyDebugView<>))]
    [DebuggerDisplay("ThreadSafetyMode={Mode}, IsValueCreated={IsValueCreated}, IsValueFaulted={IsValueFaulted}, Value={ValueForDebugDisplay}")] 
    public class Lazy
    {

        #region Inner classes 
        /// 
        /// wrapper class to box the initialized value, this is mainly created to avoid boxing/unboxing the value each time the value is called in case T is 
        /// a value type 
        /// 
        [Serializable] 
        class Boxed
        {
            internal Boxed(T value)
            { 
                m_value = value;
            } 
            internal T m_value; 
        }
 

        /// 
        /// Wrapper class to wrap the excpetion thrown by the value factory
        ///  
        class LazyInternalExceptionHolder
        { 
            internal Exception m_exception; 
            internal LazyInternalExceptionHolder(Exception ex)
            { 
                m_exception = ex;
            }
        }
        #endregion 

        // A dummy delegate used as a  : 
        // 1- Flag to avoid recursive call to Value in None and ExecutionAndPublication modes in m_valueFactory 
        // 2- Flag to PublicationOnly mode in m_threadSafeObj
        static Func PUBLICATION_ONLY_OR_ALREADY_INITIALIZED = delegate { return default(T); }; 

        //null --> value is not created
        //m_value is Boxed --> the value is created, and m_value holds the value
        //m_value is LazyExceptionHolder --> it holds an exception 
        private volatile object m_boxed;
 
        // The factory delegate that returns the value. 
        // In None and ExecutionAndPublication modes, this will be set to PUBLICATION_ONLY_OR_ALREADY_INITIALIZED as a flag to avoid recursive calls
        [NonSerialized] 
        private Func m_valueFactory;

        // null if it is not thread safe mode
        // PUBLICATION_ONLY_OR_ALREADY_INITIALIZED if PublicationOnly mode 
        // object if ExecutionAndPublication mode
        [NonSerialized] 
        private readonly object m_threadSafeObj; 

 
        /// 
        /// Initializes a new instance of the  class that
        /// uses 's default constructor for lazy initialization.
        ///  
        /// 
        /// An instance created with this constructor may be used concurrently from multiple threads. 
        ///  
        public Lazy()
            : this(LazyThreadSafetyMode.ExecutionAndPublication) 
        {
        }

        ///  
        /// Initializes a new instance of the  class that uses a
        /// specified initialization function. 
        ///  
        /// 
        /// The  invoked to produce the lazily-initialized value when it is 
        /// needed.
        /// 
        ///  is a null
        /// reference (Nothing in Visual Basic). 
        /// 
        /// An instance created with this constructor may be used concurrently from multiple threads. 
        ///  
        public Lazy(Func valueFactory)
            : this(valueFactory, LazyThreadSafetyMode.ExecutionAndPublication) 
        {
        }

        ///  
        /// Initializes a new instance of the 
        /// class that uses 's default constructor and a specified thread-safety mode. 
        ///  
        /// true if this instance should be usable by multiple threads concurrently; false if the instance will only be used by one thread at a time.
        ///  
        public Lazy(bool isThreadSafe) :
            this(isThreadSafe? LazyThreadSafetyMode.ExecutionAndPublication : LazyThreadSafetyMode.None)
        {
        } 

        ///  
        /// Initializes a new instance of the  
        /// class that uses 's default constructor and a specified thread-safety mode.
        ///  
        /// The lazy thread-safety mode mode
        ///  mode contains an invalid valuee
        public Lazy(LazyThreadSafetyMode mode)
        { 
            m_threadSafeObj = GetObjectFromMode(mode);
        } 
 

        ///  
        /// Initializes a new instance of the  class
        /// that uses a specified initialization function and a specified thread-safety mode.
        /// 
        ///  
        /// The  invoked to produce the lazily-initialized value when it is needed.
        ///  
        /// true if this instance should be usable by multiple threads concurrently; false if the instance will only be used by one thread at a time. 
        /// 
        ///  is 
        /// a null reference (Nothing in Visual Basic).
        public Lazy(Func valueFactory, bool isThreadSafe)
            : this(valueFactory, isThreadSafe ? LazyThreadSafetyMode.ExecutionAndPublication : LazyThreadSafetyMode.None)
        { 
        }
 
        ///  
        /// Initializes a new instance of the  class
        /// that uses a specified initialization function and a specified thread-safety mode. 
        /// 
        /// 
        /// The  invoked to produce the lazily-initialized value when it is needed.
        ///  
        /// The lazy thread-safety mode.
        ///  is 
        /// a null reference (Nothing in Visual Basic). 
        ///  mode contains an invalid value.
        public Lazy(Func valueFactory, LazyThreadSafetyMode mode) 
        {
            if (valueFactory == null)
                throw new ArgumentNullException("valueFactory");
 
            m_threadSafeObj = GetObjectFromMode(mode);
            m_valueFactory = valueFactory; 
        } 

        ///  
        /// Static helper function that returns an object based on the given mode. it also throws an exception if the mode is invalid
        /// 
        private static object GetObjectFromMode(LazyThreadSafetyMode mode)
        { 
            if (mode == LazyThreadSafetyMode.ExecutionAndPublication)
                return new object(); 
            else if (mode == LazyThreadSafetyMode.PublicationOnly) 
                return PUBLICATION_ONLY_OR_ALREADY_INITIALIZED;
            else if (mode != LazyThreadSafetyMode.None) 
                throw new ArgumentOutOfRangeException("mode", Environment.GetResourceString("Lazy_ctor_ModeInvalid"));

            return null; // None mode
        } 

        /// Forces initialization during serialization. 
        /// The StreamingContext for the serialization operation. 
        [OnSerializing]
        private void OnSerializing(StreamingContext context) 
        {
            // Force initialization
            T dummy = Value;
        } 

        /// Creates and returns a string representation of this instance. 
        /// The result of calling  on the .
        ///  
        /// The  is null.
        /// 
        public override string ToString()
        { 
            return IsValueCreated ? Value.ToString() : Environment.GetResourceString("Lazy_ToString_ValueNotCreated");
        } 
 
        /// Gets the value of the Lazy<T> for debugging display purposes.
        internal T ValueForDebugDisplay 
        {
            get
            {
                if (!IsValueCreated) 
                {
                    return default(T); 
                } 
                return ((Boxed)m_boxed).m_value;
            } 
        }

        /// 
        /// Gets a value indicating whether this instance may be used concurrently from multiple threads. 
        /// 
        internal LazyThreadSafetyMode Mode 
        { 
            get
            { 
                if (m_threadSafeObj == null) return LazyThreadSafetyMode.None;
                if (m_threadSafeObj == (object)PUBLICATION_ONLY_OR_ALREADY_INITIALIZED) return LazyThreadSafetyMode.PublicationOnly;
                return LazyThreadSafetyMode.ExecutionAndPublication;
            } 
        }
 
        ///  
        /// Gets whether the value creation is faulted or not
        ///  
        internal bool IsValueFaulted
        {
            get { return m_boxed is LazyInternalExceptionHolder; }
        } 

        /// Gets a value indicating whether the  has been initialized. 
        ///  
        /// true if the  instance has been initialized;
        /// otherwise, false. 
        /// 
        /// The initialization of a  instance may result in either
        /// a value being produced or an exception being thrown.  If an exception goes unhandled during initialization,
        /// the  instance is still considered initialized, and that exception 
        /// will be thrown on subsequent accesses to .  In such cases, 
        /// will return true. 
        ///  
        public bool IsValueCreated
        { 
#if !FEATURE_CORECLR && !PFX_LEGACY_3_5
            [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
#endif
            get 
            {
                return m_boxed != null && m_boxed is Boxed; 
            } 
        }
 
        /// Gets the lazily initialized value of the current .
        /// The lazily initialized value of the current . 
        /// 
        /// The  was initialized to use the default constructor 
        /// of the type being lazily initialized, and that type does not have a public, parameterless constructor. 
        /// 
        ///  
        /// The  was initialized to use the default constructor
        /// of the type being lazily initialized, and permissions to access the constructor were missing.
        /// 
        ///  
        /// The  was constructed with the  or
        ///   and the initialization function attempted to access  on this instance. 
        ///  
        /// 
        /// If  is false, accessing  will force initialization. 
        /// Please  for more information on how  will behave if an exception is thrown
        /// from initialization delegate.
        /// 
        [DebuggerBrowsable(DebuggerBrowsableState.Never)] 
        public T Value
        { 
            get 
            {
                Boxed boxed = null; 
                if (m_boxed != null )
                {
                    // Do a quick check up front for the fast path.
                    boxed = m_boxed as Boxed; 
                    if (boxed != null)
                    { 
                        return boxed.m_value; 
                    }
 
                    LazyInternalExceptionHolder exc = m_boxed as LazyInternalExceptionHolder;
                    Contract.Assert(m_boxed != null);
                    throw exc.m_exception;
                } 

                // Fall through to the slow path. 
                // We call NOCTD to abort attempts by the debugger to funceval this property (e.g. on mouseover) 
                //   (the debugger proxy is the correct way to look at state/value of this object)
#if !PFX_LEGACY_3_5 
                Debugger.NotifyOfCrossThreadDependency();
#endif
                return LazyInitValue();
 
            }
        } 
 
        /// 
        /// local helper method to initialize the value 
        /// 
        /// The inititialized T value
        private T LazyInitValue()
        { 
            Boxed boxed = null;
            LazyThreadSafetyMode mode = Mode; 
            if (mode == LazyThreadSafetyMode.None) 
            {
                boxed = CreateValue(); 
                m_boxed = boxed;
            }
            else if (mode == LazyThreadSafetyMode.PublicationOnly)
            { 
                boxed = CreateValue();
                if (Interlocked.CompareExchange(ref m_boxed, boxed, null) != null) 
                    boxed = (Boxed)m_boxed; // set the boxed value to the succeeded thread value 
            }
            else 
            {
                lock (m_threadSafeObj)
                {
                    if (m_boxed == null) 
                    {
                        boxed = CreateValue(); 
                        m_boxed = boxed; 
                    }
                    else // got the lock but the value is not null anymore, check if it is created by another thread or faulted and throw if so 
                    {
                        boxed = m_boxed as Boxed;
                        if (boxed == null) // it is not Boxed, so it is a LazyInternalExceptionHolder
                        { 
                            LazyInternalExceptionHolder exHolder = m_boxed as LazyInternalExceptionHolder;
                            Contract.Assert(exHolder != null); 
                            throw exHolder.m_exception; 
                        }
                    } 
                }
            }
            Contract.Assert(boxed != null);
            return boxed.m_value; 
        }
 
        /// Creates an instance of T using m_valueFactory in case its not null or use reflection to create a new T() 
        /// An instance of Boxed.
        private Boxed CreateValue() 
        {
            Boxed boxed = null;
            LazyThreadSafetyMode mode = Mode;
            if (m_valueFactory != null) 
            {
                try 
                { 
                    // check for recursion
                    if (mode != LazyThreadSafetyMode.PublicationOnly && m_valueFactory == PUBLICATION_ONLY_OR_ALREADY_INITIALIZED) 
                        throw new InvalidOperationException(Environment.GetResourceString("Lazy_Value_RecursiveCallsToValue"));

                    Func factory = m_valueFactory;
                    if (mode != LazyThreadSafetyMode.PublicationOnly) // only detect recursion on None and ExecutionAndPublication modes 
                        m_valueFactory = PUBLICATION_ONLY_OR_ALREADY_INITIALIZED;
                    boxed = new Boxed(factory()); 
                } 
                catch (Exception ex)
                { 
                    if (mode != LazyThreadSafetyMode.PublicationOnly) // don't cache the exception for PublicationOnly mode
                    {
#if PFX_LEGACY_3_5
                    m_boxed = new LazyInternalExceptionHolder(ex); 
#else
                        m_boxed = new LazyInternalExceptionHolder(ex.PrepForRemoting());// copy the call stack by calling the internal method PrepForRemoting 
#endif 
                    }
                    throw; 
                }
            }
            else
            { 
                try
                { 
                    boxed = new Boxed((T)Activator.CreateInstance(typeof(T))); 

                } 
                catch (System.MissingMethodException)
                {
                    Exception ex = new System.MissingMemberException(Environment.GetResourceString("Lazy_CreateValue_NoParameterlessCtorForT"));
                    if (mode != LazyThreadSafetyMode.PublicationOnly) // don't cache the exception for PublicationOnly mode 
                        m_boxed = new LazyInternalExceptionHolder(ex);
                    throw ex; 
                } 
            }
 
            return boxed;
        }

    } 

    /// A debugger view of the Lazy<T> to surface additional debugging properties and 
    /// to ensure that the Lazy<T> does not become initialized if it was not already. 
    internal sealed class System_LazyDebugView
    { 
        //The Lazy object being viewed.
        private readonly Lazy m_lazy;

        /// Constructs a new debugger view object for the provided Lazy object. 
        /// A Lazy object to browse in the debugger.
        public System_LazyDebugView(Lazy lazy) 
        { 
            m_lazy = lazy;
        } 

        /// Returns whether the Lazy object is initialized or not.
        public bool IsValueCreated
        { 
            get { return m_lazy.IsValueCreated; }
        } 
 
        /// Returns the value of the Lazy object.
        public T Value 
        {
            get
            { return m_lazy.ValueForDebugDisplay; }
        } 

        /// Returns the execution mode of the Lazy object 
        public LazyThreadSafetyMode Mode 
        {
            get { return m_lazy.Mode; } 
        }

        /// Returns the execution mode of the Lazy object
        public bool IsValueFaulted 
        {
            get { return m_lazy.IsValueFaulted; } 
        } 

    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK