view Implab/Components/LazyAndWeak.cs @ 279:8714471e8d78 v3

Container configuration cleanup, RC2
author cin
date Fri, 04 May 2018 18:12:42 +0300
parents 3a6e18c432be
children
line wrap: on
line source

using System;
using System.Threading;

namespace Implab.Components {
    /// <summary>
    /// Creates an instace on-demand and allows it to be garbage collected.
    /// </summary>
    /// <remarks>
    /// Usefull when dealing with memory-intensive objects which are frequently used.
    /// This class is similar to <see cref="ObjectPool{T}"/> except it is a singleton.
    /// This class can't be used to hold diposable objects.
    /// </remarks>
    public class LazyAndWeak<T> where T : class {

        readonly Func<T> m_factory;
        readonly object m_lock;
        WeakReference m_reference;


        public LazyAndWeak(Func<T> factory, bool useLock) {
            Safe.ArgumentNotNull(factory, "factory");
            m_factory = factory;
            m_lock = useLock ? new object() : null;
        }

        public LazyAndWeak(Func<T> factory) : this(factory, false) {
        }

        public T Value {
            get {
                while (true) {
                    var weak = m_reference;
                    T value;
                    if (weak != null) {
                        value = weak.Target as T;
                        if (value != null)
                            return value;
                    }

                    if (m_lock == null) {
                        value = m_factory();

                        if (Interlocked.CompareExchange(ref m_reference, new WeakReference(value), weak) == weak)
                            return value;
                    } else {
                        lock (m_lock) {
                            // double check
                            weak = m_reference;
                            if (weak != null) {
                                value = weak.Target as T;
                                if (value != null)
                                    return value;
                            }
                            // we are safe to write
                            value = m_factory();
                            m_reference = new WeakReference(value);
                            return value;
                        }
                    }
                }
            }
        }
    }
}