mscorlib(4.0.0.0) API with additions
Lazy.cs
1 using System.Diagnostics;
6 using System.Threading;
7 
8 namespace System
9 {
12  [Serializable]
13  [ComVisible(false)]
14  [DebuggerTypeProxy(typeof(System_LazyDebugView<>))]
15  [DebuggerDisplay("ThreadSafetyMode={Mode}, IsValueCreated={IsValueCreated}, IsValueFaulted={IsValueFaulted}, Value={ValueForDebugDisplay}")]
16  [__DynamicallyInvokable]
17  [HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)]
18  public class Lazy<T>
19  {
20  [Serializable]
21  private class Boxed
22  {
23  internal T m_value;
24 
25  internal Boxed(T value)
26  {
27  m_value = value;
28  }
29  }
30 
31  private class LazyInternalExceptionHolder
32  {
33  internal ExceptionDispatchInfo m_edi;
34 
35  internal LazyInternalExceptionHolder(Exception ex)
36  {
37  m_edi = ExceptionDispatchInfo.Capture(ex);
38  }
39  }
40 
41  private static readonly Func<T> ALREADY_INVOKED_SENTINEL = () => default(T);
42 
43  private object m_boxed;
44 
45  [NonSerialized]
46  private Func<T> m_valueFactory;
47 
48  [NonSerialized]
49  private object m_threadSafeObj;
50 
51  internal T ValueForDebugDisplay
52  {
53  get
54  {
55  if (!IsValueCreated)
56  {
57  return default(T);
58  }
59  return ((Boxed)m_boxed).m_value;
60  }
61  }
62 
63  internal LazyThreadSafetyMode Mode
64  {
65  get
66  {
67  if (m_threadSafeObj == null)
68  {
69  return LazyThreadSafetyMode.None;
70  }
71  if (m_threadSafeObj == LazyHelpers.PUBLICATION_ONLY_SENTINEL)
72  {
73  return LazyThreadSafetyMode.PublicationOnly;
74  }
75  return LazyThreadSafetyMode.ExecutionAndPublication;
76  }
77  }
78 
79  internal bool IsValueFaulted => m_boxed is LazyInternalExceptionHolder;
80 
84  [__DynamicallyInvokable]
85  public bool IsValueCreated
86  {
87  [__DynamicallyInvokable]
88  get
89  {
90  if (m_boxed != null)
91  {
92  return m_boxed is Boxed;
93  }
94  return false;
95  }
96  }
97 
103  [DebuggerBrowsable(DebuggerBrowsableState.Never)]
104  [__DynamicallyInvokable]
105  public T Value
106  {
107  [__DynamicallyInvokable]
108  get
109  {
110  Boxed boxed = null;
111  if (m_boxed != null)
112  {
113  boxed = (m_boxed as Boxed);
114  if (boxed != null)
115  {
116  return boxed.m_value;
117  }
118  LazyInternalExceptionHolder lazyInternalExceptionHolder = m_boxed as LazyInternalExceptionHolder;
119  lazyInternalExceptionHolder.m_edi.Throw();
120  }
122  return LazyInitValue();
123  }
124  }
125 
127  [__DynamicallyInvokable]
128  public Lazy()
130  {
131  }
132 
137  [__DynamicallyInvokable]
138  public Lazy(Func<T> valueFactory)
139  : this(valueFactory, LazyThreadSafetyMode.ExecutionAndPublication)
140  {
141  }
142 
146  [__DynamicallyInvokable]
147  public Lazy(bool isThreadSafe)
149  {
150  }
151 
156  [__DynamicallyInvokable]
158  {
159  m_threadSafeObj = GetObjectFromMode(mode);
160  }
161 
168  [__DynamicallyInvokable]
169  public Lazy(Func<T> valueFactory, bool isThreadSafe)
170  : this(valueFactory, isThreadSafe ? LazyThreadSafetyMode.ExecutionAndPublication : LazyThreadSafetyMode.None)
171  {
172  }
173 
181  [__DynamicallyInvokable]
182  public Lazy(Func<T> valueFactory, LazyThreadSafetyMode mode)
183  {
184  if (valueFactory == null)
185  {
186  throw new ArgumentNullException("valueFactory");
187  }
188  m_threadSafeObj = GetObjectFromMode(mode);
189  m_valueFactory = valueFactory;
190  }
191 
192  private static object GetObjectFromMode(LazyThreadSafetyMode mode)
193  {
194  switch (mode)
195  {
196  case LazyThreadSafetyMode.ExecutionAndPublication:
197  return new object();
198  case LazyThreadSafetyMode.PublicationOnly:
199  return LazyHelpers.PUBLICATION_ONLY_SENTINEL;
200  default:
201  throw new ArgumentOutOfRangeException("mode", Environment.GetResourceString("Lazy_ctor_ModeInvalid"));
202  case LazyThreadSafetyMode.None:
203  return null;
204  }
205  }
206 
207  [OnSerializing]
208  private void OnSerializing(StreamingContext context)
209  {
210  T value = Value;
211  }
212 
216  [__DynamicallyInvokable]
217  public override string ToString()
218  {
219  if (!IsValueCreated)
220  {
221  return Environment.GetResourceString("Lazy_ToString_ValueNotCreated");
222  }
223  return Value.ToString();
224  }
225 
226  private T LazyInitValue()
227  {
228  Boxed boxed = null;
229  switch (Mode)
230  {
231  case LazyThreadSafetyMode.None:
232  boxed = (Boxed)(m_boxed = CreateValue());
233  break;
234  case LazyThreadSafetyMode.PublicationOnly:
235  boxed = CreateValue();
236  if (boxed == null || Interlocked.CompareExchange(ref m_boxed, boxed, null) != null)
237  {
238  boxed = (Boxed)m_boxed;
239  }
240  else
241  {
242  m_valueFactory = ALREADY_INVOKED_SENTINEL;
243  }
244  break;
245  default:
246  {
247  object obj = Volatile.Read(ref m_threadSafeObj);
248  bool lockTaken = false;
249  try
250  {
251  if (obj != ALREADY_INVOKED_SENTINEL)
252  {
253  Monitor.Enter(obj, ref lockTaken);
254  }
255  if (m_boxed == null)
256  {
257  boxed = (Boxed)(m_boxed = CreateValue());
258  Volatile.Write(ref m_threadSafeObj, ALREADY_INVOKED_SENTINEL);
259  }
260  else
261  {
262  boxed = (m_boxed as Boxed);
263  if (boxed == null)
264  {
265  LazyInternalExceptionHolder lazyInternalExceptionHolder = m_boxed as LazyInternalExceptionHolder;
266  lazyInternalExceptionHolder.m_edi.Throw();
267  }
268  }
269  }
270  finally
271  {
272  if (lockTaken)
273  {
274  Monitor.Exit(obj);
275  }
276  }
277  break;
278  }
279  }
280  return boxed.m_value;
281  }
282 
283  private Boxed CreateValue()
284  {
285  Boxed boxed = null;
286  LazyThreadSafetyMode mode = Mode;
287  if (m_valueFactory != null)
288  {
289  try
290  {
291  if (mode != LazyThreadSafetyMode.PublicationOnly && m_valueFactory == ALREADY_INVOKED_SENTINEL)
292  {
293  throw new InvalidOperationException(Environment.GetResourceString("Lazy_Value_RecursiveCallsToValue"));
294  }
295  Func<T> valueFactory = m_valueFactory;
296  if (mode != LazyThreadSafetyMode.PublicationOnly)
297  {
298  m_valueFactory = ALREADY_INVOKED_SENTINEL;
299  }
300  else if (valueFactory == ALREADY_INVOKED_SENTINEL)
301  {
302  return null;
303  }
304  return new Boxed(valueFactory());
305  }
306  catch (Exception ex)
307  {
308  if (mode != LazyThreadSafetyMode.PublicationOnly)
309  {
310  m_boxed = new LazyInternalExceptionHolder(ex);
311  }
312  throw;
313  }
314  }
315  try
316  {
317  return new Boxed((T)Activator.CreateInstance(typeof(T)));
318  }
319  catch (MissingMethodException)
320  {
321  Exception ex2 = new MissingMemberException(Environment.GetResourceString("Lazy_CreateValue_NoParameterlessCtorForT"));
322  if (mode != LazyThreadSafetyMode.PublicationOnly)
323  {
324  m_boxed = new LazyInternalExceptionHolder(ex2);
325  }
326  throw ex2;
327  }
328  }
329  }
330 }
The exception that is thrown when a null reference (Nothing in Visual Basic) is passed to a method th...
static void Write(ref bool location, bool value)
Writes the specified value to the specified field. On systems that require it, inserts a memory barri...
Definition: Volatile.cs:186
override string ToString()
Creates and returns a string representation of the P:System.Lazy`1.Value property for this instance.
Definition: Lazy.cs:217
Lazy()
Initializes a new instance of the T:System.Lazy`1 class. When lazy initialization occurs,...
Definition: Lazy.cs:128
Definition: __Canon.cs:3
T Value
Gets the lazily initialized value of the current T:System.Lazy`1 instance.
Definition: Lazy.cs:106
The exception that is thrown when the value of an argument is outside the allowable range of values a...
Provides a mechanism that synchronizes access to objects.
Definition: Monitor.cs:13
Describes the source and destination of a given serialized stream, and provides an additional caller-...
static ExceptionDispatchInfo Capture(Exception source)
Creates an T:System.Runtime.ExceptionServices.ExceptionDispatchInfo object that represents the specif...
Lazy(LazyThreadSafetyMode mode)
Initializes a new instance of the T:System.Lazy`1 class that uses the default constructor of T and t...
Definition: Lazy.cs:157
Represents an exception whose state is captured at a certain point in code.
SecurityAction
Specifies the security actions that can be performed using declarative security.
static void Enter(object obj)
Acquires an exclusive lock on the specified object.
Provides information about, and means to manipulate, the current environment and platform....
Definition: Environment.cs:21
static int CompareExchange(ref int location1, int value, int comparand)
Compares two 32-bit signed integers for equality and, if they are equal, replaces the first value.
Lazy(Func< T > valueFactory, LazyThreadSafetyMode mode)
Initializes a new instance of the T:System.Lazy`1 class that uses the specified initialization functi...
Definition: Lazy.cs:182
static void Exit(object obj)
Releases an exclusive lock on the specified object.
Lazy(Func< T > valueFactory)
Initializes a new instance of the T:System.Lazy`1 class. When lazy initialization occurs,...
Definition: Lazy.cs:138
Contains methods for performing volatile memory operations.
Definition: Volatile.cs:8
Enables communication with a debugger. This class cannot be inherited.
Definition: Debugger.cs:11
static bool Read(ref bool location)
Reads the value of the specified field. On systems that require it, inserts a memory barrier that pre...
Definition: Volatile.cs:15
Locks are used to ensure that only a single thread can initialize a T:System.Lazy`1 instance in a thr...
Provides support for lazy initialization.
Definition: Lazy.cs:18
bool IsValueCreated
Gets a value that indicates whether a value has been created for this T:System.Lazy`1 instance.
Definition: Lazy.cs:86
Represents errors that occur during application execution.To browse the .NET Framework source code fo...
Definition: Exception.cs:22
Specifies that the class can be serialized.
static void NotifyOfCrossThreadDependency()
Notifies a debugger that execution is about to enter a path that involves a cross-thread dependency.
Definition: Debugger.cs:104
DebuggerBrowsableState
Provides display instructions for the debugger.
LazyThreadSafetyMode
Specifies how a T:System.Lazy`1 instance synchronizes access among multiple threads.
Provides atomic operations for variables that are shared by multiple threads.
Definition: Interlocked.cs:10