178
|
1 using System;
|
|
2 using System.Threading;
|
|
3
|
|
4 namespace Implab.Components {
|
180
|
5 /// <summary>
|
|
6 /// Creates an instace on-demand and allows it to be garbage collected.
|
|
7 /// </summary>
|
|
8 /// <remarks>
|
|
9 /// Usefull when dealing with memory-intensive objects which are frequently used.
|
182
|
10 /// This class is similar to <see cref="ObjectPool{T}"/> except it is a singleton.
|
264
|
11 /// This class can't be used to hold diposable objects.
|
180
|
12 /// </remarks>
|
178
|
13 public class LazyAndWeak<T> where T : class {
|
|
14
|
|
15 readonly Func<T> m_factory;
|
|
16 readonly object m_lock;
|
|
17 WeakReference m_reference;
|
|
18
|
|
19
|
|
20 public LazyAndWeak(Func<T> factory, bool useLock) {
|
|
21 Safe.ArgumentNotNull(factory, "factory");
|
|
22 m_factory = factory;
|
|
23 m_lock = useLock ? new object() : null;
|
|
24 }
|
|
25
|
|
26 public LazyAndWeak(Func<T> factory) : this(factory, false) {
|
|
27 }
|
|
28
|
|
29 public T Value {
|
|
30 get {
|
|
31 while (true) {
|
|
32 var weak = m_reference;
|
|
33 T value;
|
|
34 if (weak != null) {
|
|
35 value = weak.Target as T;
|
|
36 if (value != null)
|
|
37 return value;
|
|
38 }
|
|
39
|
|
40 if (m_lock == null) {
|
|
41 value = m_factory();
|
|
42
|
|
43 if (Interlocked.CompareExchange(ref m_reference, new WeakReference(value), weak) == weak)
|
|
44 return value;
|
|
45 } else {
|
180
|
46 lock (m_lock) {
|
|
47 // double check
|
182
|
48 weak = m_reference;
|
180
|
49 if (weak != null) {
|
|
50 value = weak.Target as T;
|
|
51 if (value != null)
|
|
52 return value;
|
|
53 }
|
|
54 // we are safe to write
|
|
55 value = m_factory();
|
|
56 m_reference = new WeakReference(value);
|
|
57 return value;
|
|
58 }
|
178
|
59 }
|
|
60 }
|
|
61 }
|
|
62 }
|
|
63 }
|
|
64 }
|
|
65
|