LazyAndWeak.cs
64 lines
| 2.1 KiB
| text/x-csharp
|
CSharpLexer
|
|
r178 | using System; | ||
| using System.Threading; | ||||
| namespace Implab.Components { | ||||
|
|
r180 | /// <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. | ||||
|
|
r182 | /// This class is similar to <see cref="ObjectPool{T}"/> except it is a singleton. | ||
|
|
r180 | /// </remarks> | ||
|
|
r178 | 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 { | ||||
|
|
r180 | lock (m_lock) { | ||
| // double check | ||||
|
|
r182 | weak = m_reference; | ||
|
|
r180 | 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; | ||||
| } | ||||
|
|
r178 | } | ||
| } | ||||
| } | ||||
| } | ||||
| } | ||||
| } | ||||
