/Aurora/Framework/Utilities/Lazy.cs

https://bitbucket.org/VirtualReality/software-testing · C# · 264 lines · 185 code · 23 blank · 56 comment · 21 complexity · a7cb7d63c69896baea39f568623e08dd MD5 · raw file

  1. /*
  2. * Copyright (c) Contributors, http://aurora-sim.org/, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the Aurora-Sim Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. //
  28. // Lazy.cs
  29. //
  30. // Authors:
  31. // Zoltan Varga (vargaz@gmail.com)
  32. // Marek Safar (marek.safar@gmail.com)
  33. //
  34. // Copyright (C) 2009 Novell
  35. //
  36. // Permission is hereby granted, free of charge, to any person obtaining
  37. // a copy of this software and associated documentation files (the
  38. // "Software"), to deal in the Software without restriction, including
  39. // without limitation the rights to use, copy, modify, merge, publish,
  40. // distribute, sublicense, and/or sell copies of the Software, and to
  41. // permit persons to whom the Software is furnished to do so, subject to
  42. // the following conditions:
  43. //
  44. // The above copyright notice and this permission notice shall be
  45. // included in all copies or substantial portions of the Software.
  46. //
  47. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  48. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  49. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  50. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  51. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  52. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  53. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  54. //
  55. using System;
  56. using System.Diagnostics;
  57. using System.Runtime.InteropServices;
  58. using System.Security.Permissions;
  59. using System.Threading;
  60. namespace Aurora.Framework.Utilities
  61. {
  62. public enum LazyThreadSafetyMode
  63. {
  64. None,
  65. PublicationOnly,
  66. ExecutionAndPublication
  67. }
  68. [Serializable]
  69. [ComVisible(false)]
  70. [HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)]
  71. public class Lazy<T>
  72. {
  73. private readonly LazyThreadSafetyMode mode;
  74. private readonly object monitor;
  75. private Exception exception;
  76. private Func<T> factory;
  77. private bool inited;
  78. private T value;
  79. public Lazy()
  80. : this(LazyThreadSafetyMode.ExecutionAndPublication)
  81. {
  82. }
  83. public Lazy(Func<T> valueFactory)
  84. : this(valueFactory, LazyThreadSafetyMode.ExecutionAndPublication)
  85. {
  86. }
  87. public Lazy(bool isThreadSafe)
  88. : this(
  89. Activator.CreateInstance<T>,
  90. isThreadSafe ? LazyThreadSafetyMode.ExecutionAndPublication : LazyThreadSafetyMode.None)
  91. {
  92. }
  93. public Lazy(Func<T> valueFactory, bool isThreadSafe)
  94. : this(valueFactory, isThreadSafe ? LazyThreadSafetyMode.ExecutionAndPublication : LazyThreadSafetyMode.None
  95. )
  96. {
  97. }
  98. public Lazy(LazyThreadSafetyMode mode)
  99. : this(Activator.CreateInstance<T>, mode)
  100. {
  101. }
  102. public Lazy(Func<T> valueFactory, LazyThreadSafetyMode mode)
  103. {
  104. if (valueFactory == null)
  105. throw new ArgumentNullException("valueFactory");
  106. this.factory = valueFactory;
  107. if (mode != LazyThreadSafetyMode.None)
  108. monitor = new object();
  109. this.mode = mode;
  110. }
  111. // Don't trigger expensive initialization
  112. [DebuggerBrowsable(DebuggerBrowsableState.Never)]
  113. public T Value
  114. {
  115. get
  116. {
  117. if (inited)
  118. return value;
  119. if (exception != null)
  120. throw exception;
  121. return InitValue();
  122. }
  123. }
  124. public bool IsValueCreated
  125. {
  126. get { return inited; }
  127. }
  128. private T InitValue()
  129. {
  130. switch (mode)
  131. {
  132. case LazyThreadSafetyMode.None:
  133. {
  134. var init_factory = factory;
  135. if (init_factory == null)
  136. throw exception =
  137. new InvalidOperationException(
  138. "The initialization function tries to access Value on this instance");
  139. try
  140. {
  141. factory = null;
  142. T v = init_factory();
  143. value = v;
  144. Thread.MemoryBarrier();
  145. inited = true;
  146. }
  147. catch (Exception ex)
  148. {
  149. exception = ex;
  150. throw;
  151. }
  152. break;
  153. }
  154. case LazyThreadSafetyMode.PublicationOnly:
  155. {
  156. var init_factory = factory;
  157. T v;
  158. //exceptions are ignored
  159. v = init_factory != null ? init_factory() : default(T);
  160. lock (monitor)
  161. {
  162. if (inited)
  163. return value;
  164. value = v;
  165. Thread.MemoryBarrier();
  166. inited = true;
  167. factory = null;
  168. }
  169. break;
  170. }
  171. case LazyThreadSafetyMode.ExecutionAndPublication:
  172. {
  173. lock (monitor)
  174. {
  175. if (inited)
  176. return value;
  177. if (factory == null)
  178. throw exception =
  179. new InvalidOperationException(
  180. "The initialization function tries to access Value on this instance");
  181. var init_factory = factory;
  182. try
  183. {
  184. factory = null;
  185. T v = init_factory();
  186. value = v;
  187. Thread.MemoryBarrier();
  188. inited = true;
  189. }
  190. catch (Exception ex)
  191. {
  192. exception = ex;
  193. throw;
  194. }
  195. }
  196. break;
  197. }
  198. default:
  199. throw new InvalidOperationException("Invalid LazyThreadSafetyMode " + mode);
  200. }
  201. if (monitor == null)
  202. {
  203. value = factory();
  204. inited = true;
  205. }
  206. else
  207. {
  208. lock (monitor)
  209. {
  210. if (inited)
  211. return value;
  212. if (factory == null)
  213. throw new InvalidOperationException(
  214. "The initialization function tries to access Value on this instance");
  215. var init_factory = factory;
  216. try
  217. {
  218. factory = null;
  219. T v = init_factory();
  220. value = v;
  221. Thread.MemoryBarrier();
  222. inited = true;
  223. }
  224. catch
  225. {
  226. factory = init_factory;
  227. throw;
  228. }
  229. }
  230. }
  231. return value;
  232. }
  233. public override string ToString()
  234. {
  235. if (inited)
  236. return value.ToString();
  237. else
  238. return "Value is not created";
  239. }
  240. }
  241. }