blob: 4094dcef87c4673cf44989c322b3be73ea11b61c (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
#if NO_LAZY
#pragma warning disable 0420
//
// Based on ndp\clr\src\BCL\System\Lazy.cs but with LazyThreadSafetyMode.ExecutionAndPublication mode behavior hardcoded.
//
using System.Diagnostics;
using System.Threading;
using System.Reactive;
namespace System
{
internal class Lazy<T>
{
class Boxed
{
internal Boxed(T value)
{
m_value = value;
}
internal T m_value;
}
static Func<T> ALREADY_INVOKED_SENTINEL = delegate { return default(T); };
private object m_boxed;
private Func<T> m_valueFactory;
private volatile object m_threadSafeObj;
public Lazy(Func<T> valueFactory)
{
m_threadSafeObj = new object();
m_valueFactory = valueFactory;
}
#if !NO_DEBUGGER_ATTRIBUTES
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
#endif
public T Value
{
get
{
Boxed boxed = null;
if (m_boxed != null)
{
boxed = m_boxed as Boxed;
if (boxed != null)
{
return boxed.m_value;
}
var exc = m_boxed as Exception;
exc.Throw();
}
return LazyInitValue();
}
}
private T LazyInitValue()
{
Boxed boxed = null;
object threadSafeObj = m_threadSafeObj;
bool lockTaken = false;
try
{
if (threadSafeObj != (object)ALREADY_INVOKED_SENTINEL)
{
Monitor.Enter(threadSafeObj);
lockTaken = true;
}
if (m_boxed == null)
{
boxed = CreateValue();
m_boxed = boxed;
m_threadSafeObj = ALREADY_INVOKED_SENTINEL;
}
else
{
boxed = m_boxed as Boxed;
if (boxed == null)
{
var exc = m_boxed as Exception;
exc.Throw();
}
}
}
finally
{
if (lockTaken)
Monitor.Exit(threadSafeObj);
}
return boxed.m_value;
}
private Boxed CreateValue()
{
Boxed boxed = null;
try
{
if (m_valueFactory == ALREADY_INVOKED_SENTINEL)
throw new InvalidOperationException();
Func<T> factory = m_valueFactory;
m_valueFactory = ALREADY_INVOKED_SENTINEL;
boxed = new Boxed(factory());
}
catch (Exception ex)
{
m_boxed = ex;
throw;
}
return boxed;
}
}
}
#pragma warning restore 0420
#endif
|