// dnlib: See LICENSE.txt for more info using System; using System.Diagnostics; using dnlib.Threading; namespace dnlib.Utils { /// /// Lazily returns the original value if the user hasn't overwritten the value /// /// Value type [DebuggerDisplay("{value}")] struct UserValue { #if THREAD_SAFE Lock theLock; #endif Func readOriginalValue; TValue value; bool isUserValue; bool isValueInitialized; #if THREAD_SAFE /// /// Sets the lock that protects the data /// public Lock Lock { set => theLock = value; } #endif /// /// Set a delegate instance that will return the original value /// public Func ReadOriginalValue { set => readOriginalValue = value; } /// /// Gets/sets the value /// /// The getter returns the original value if the value hasn't been initialized. public TValue Value { get { #if THREAD_SAFE theLock?.EnterWriteLock(); try { #endif if (!isValueInitialized) { value = readOriginalValue(); readOriginalValue = null; isValueInitialized = true; } return value; #if THREAD_SAFE } finally { theLock?.ExitWriteLock(); } #endif } set { #if THREAD_SAFE theLock?.EnterWriteLock(); try { #endif this.value = value; readOriginalValue = null; isUserValue = true; isValueInitialized = true; #if THREAD_SAFE } finally { theLock?.ExitWriteLock(); } #endif } } /// /// Returns true if the value has been initialized /// public bool IsValueInitialized { #if THREAD_SAFE get { theLock?.EnterReadLock(); try { return isValueInitialized; } finally { theLock?.ExitReadLock(); } } #else get => isValueInitialized; #endif } /// /// Returns true if the value was set by the user /// public bool IsUserValue { #if THREAD_SAFE get { theLock?.EnterReadLock(); try { return isUserValue; } finally { theLock?.ExitReadLock(); } } #else get => isUserValue; #endif } } }