Memoizer.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / ndp / fx / src / DataEntity / System / Data / Common / Utils / Memoizer.cs / 1 / Memoizer.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner  	 [....], [....]
//--------------------------------------------------------------------- 
 
using System.Collections.Generic;
using System.Threading; 
using System.Diagnostics;
namespace System.Data.Common.Utils
{
    ///  
    /// Remembers the result of evaluating an expensive function so that subsequent
    /// evaluations are faster. Thread-safe. 
    ///  
    /// Type of the argument to the function.
    /// Type of the function result. 
    internal sealed class Memoizer
    {
        private readonly Func _function;
        private readonly Dictionary _resultCache; 
        private readonly ReaderWriterLockSlim _lock;
 
        ///  
        /// Constructs
        ///  
        /// Required. Function whose values are being cached.
        /// Optional. Comparer used to determine if two functions arguments
        /// are the same.
        internal Memoizer(Func function, IEqualityComparer argComparer) 
        {
            EntityUtil.CheckArgumentNull(function, "function"); 
 
            _function = function;
            _resultCache = new Dictionary(argComparer); 
            _lock = new ReaderWriterLockSlim();
        }

        ///  
        /// Evaluates the wrapped function for the given argument. If the function has already
        /// been evaluated for the given argument, returns cached value. Otherwise, the value 
        /// is computed and returned. 
        /// 
        /// Function argument. 
        /// Function result.
        internal TResult Evaluate(TArg arg)
        {
            Result result; 
            bool hasResult;
 
            // check to see if a result has already been computed 
            _lock.EnterReadLock();
            try 
            {
                hasResult = _resultCache.TryGetValue(arg, out result);
            }
            finally 
            {
                _lock.ExitReadLock(); 
            } 

            if (!hasResult) 
            {
                // compute the new value
                _lock.EnterWriteLock();
                try 
                {
                    // see if the value has been computed in the interim 
                    if (!_resultCache.TryGetValue(arg, out result)) 
                    {
                        result = new Result(() => _function(arg)); 
                        _resultCache.Add(arg, result);
                    }
                }
                finally 
                {
                    _lock.ExitWriteLock(); 
                } 
            }
 
            // note: you need to release the global cache lock before (potentially) acquiring
            // a result lock in result.GetValue()
            return result.GetValue();
        } 

        ///  
        /// Encapsulates a 'deferred' result. The result is constructed with a delegate (must not 
        /// be null) and when the user requests a value the delegate is invoked and stored.
        ///  
        private class Result
        {
            private TResult _value;
            private Func _delegate; 

            internal Result(Func createValueDelegate) 
            { 
                Debug.Assert(null != createValueDelegate, "delegate must be given");
                _delegate = createValueDelegate; 
            }

            internal TResult GetValue()
            { 
                if (null == _delegate)
                { 
                    // if the delegate has been cleared, it means we have already computed the value 
                    return _value;
                } 

                // lock the entry while computing the value so that two threads
                // don't simultaneously do the work
                lock (this) 
                {
                    if (null == _delegate) 
                    { 
                        // between our initial check and our acquisition of the lock, some other
                        // thread may have computed the value 
                        return _value;
                    }
                    _value = _delegate();
 
                    // ensure _delegate (and its closure) is garbage collected, and set to null
                    // to indicate that the value has been computed 
                    _delegate = null; 
                    return _value;
                } 
            }
        }
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner  	 [....], [....]
//--------------------------------------------------------------------- 
 
using System.Collections.Generic;
using System.Threading; 
using System.Diagnostics;
namespace System.Data.Common.Utils
{
    ///  
    /// Remembers the result of evaluating an expensive function so that subsequent
    /// evaluations are faster. Thread-safe. 
    ///  
    /// Type of the argument to the function.
    /// Type of the function result. 
    internal sealed class Memoizer
    {
        private readonly Func _function;
        private readonly Dictionary _resultCache; 
        private readonly ReaderWriterLockSlim _lock;
 
        ///  
        /// Constructs
        ///  
        /// Required. Function whose values are being cached.
        /// Optional. Comparer used to determine if two functions arguments
        /// are the same.
        internal Memoizer(Func function, IEqualityComparer argComparer) 
        {
            EntityUtil.CheckArgumentNull(function, "function"); 
 
            _function = function;
            _resultCache = new Dictionary(argComparer); 
            _lock = new ReaderWriterLockSlim();
        }

        ///  
        /// Evaluates the wrapped function for the given argument. If the function has already
        /// been evaluated for the given argument, returns cached value. Otherwise, the value 
        /// is computed and returned. 
        /// 
        /// Function argument. 
        /// Function result.
        internal TResult Evaluate(TArg arg)
        {
            Result result; 
            bool hasResult;
 
            // check to see if a result has already been computed 
            _lock.EnterReadLock();
            try 
            {
                hasResult = _resultCache.TryGetValue(arg, out result);
            }
            finally 
            {
                _lock.ExitReadLock(); 
            } 

            if (!hasResult) 
            {
                // compute the new value
                _lock.EnterWriteLock();
                try 
                {
                    // see if the value has been computed in the interim 
                    if (!_resultCache.TryGetValue(arg, out result)) 
                    {
                        result = new Result(() => _function(arg)); 
                        _resultCache.Add(arg, result);
                    }
                }
                finally 
                {
                    _lock.ExitWriteLock(); 
                } 
            }
 
            // note: you need to release the global cache lock before (potentially) acquiring
            // a result lock in result.GetValue()
            return result.GetValue();
        } 

        ///  
        /// Encapsulates a 'deferred' result. The result is constructed with a delegate (must not 
        /// be null) and when the user requests a value the delegate is invoked and stored.
        ///  
        private class Result
        {
            private TResult _value;
            private Func _delegate; 

            internal Result(Func createValueDelegate) 
            { 
                Debug.Assert(null != createValueDelegate, "delegate must be given");
                _delegate = createValueDelegate; 
            }

            internal TResult GetValue()
            { 
                if (null == _delegate)
                { 
                    // if the delegate has been cleared, it means we have already computed the value 
                    return _value;
                } 

                // lock the entry while computing the value so that two threads
                // don't simultaneously do the work
                lock (this) 
                {
                    if (null == _delegate) 
                    { 
                        // between our initial check and our acquisition of the lock, some other
                        // thread may have computed the value 
                        return _value;
                    }
                    _value = _delegate();
 
                    // ensure _delegate (and its closure) is garbage collected, and set to null
                    // to indicate that the value has been computed 
                    _delegate = null; 
                    return _value;
                } 
            }
        }
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

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