/Aurora/Framework/Utilities/Lazy.cs
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// 29// Lazy.cs 30// 31// Authors: 32// Zoltan Varga (vargaz@gmail.com) 33// Marek Safar (marek.safar@gmail.com) 34// 35// Copyright (C) 2009 Novell 36// 37// Permission is hereby granted, free of charge, to any person obtaining 38// a copy of this software and associated documentation files (the 39// "Software"), to deal in the Software without restriction, including 40// without limitation the rights to use, copy, modify, merge, publish, 41// distribute, sublicense, and/or sell copies of the Software, and to 42// permit persons to whom the Software is furnished to do so, subject to 43// the following conditions: 44// 45// The above copyright notice and this permission notice shall be 46// included in all copies or substantial portions of the Software. 47// 48// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 49// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 50// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 51// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 52// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 53// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 54// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 55// 56 57using System; 58using System.Diagnostics; 59using System.Runtime.InteropServices; 60using System.Security.Permissions; 61using System.Threading; 62 63namespace Aurora.Framework.Utilities 64{ 65 public enum LazyThreadSafetyMode 66 { 67 None, 68 PublicationOnly, 69 ExecutionAndPublication 70 } 71 72 [Serializable] 73 [ComVisible(false)] 74 [HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)] 75 public class Lazy<T> 76 { 77 private readonly LazyThreadSafetyMode mode; 78 private readonly object monitor; 79 private Exception exception; 80 private Func<T> factory; 81 private bool inited; 82 private T value; 83 84 public Lazy() 85 : this(LazyThreadSafetyMode.ExecutionAndPublication) 86 { 87 } 88 89 public Lazy(Func<T> valueFactory) 90 : this(valueFactory, LazyThreadSafetyMode.ExecutionAndPublication) 91 { 92 } 93 94 public Lazy(bool isThreadSafe) 95 : this( 96 Activator.CreateInstance<T>, 97 isThreadSafe ? LazyThreadSafetyMode.ExecutionAndPublication : LazyThreadSafetyMode.None) 98 { 99 } 100 101 public Lazy(Func<T> valueFactory, bool isThreadSafe) 102 : this(valueFactory, isThreadSafe ? LazyThreadSafetyMode.ExecutionAndPublication : LazyThreadSafetyMode.None 103 ) 104 { 105 } 106 107 public Lazy(LazyThreadSafetyMode mode) 108 : this(Activator.CreateInstance<T>, mode) 109 { 110 } 111 112 public Lazy(Func<T> valueFactory, LazyThreadSafetyMode mode) 113 { 114 if (valueFactory == null) 115 throw new ArgumentNullException("valueFactory"); 116 this.factory = valueFactory; 117 if (mode != LazyThreadSafetyMode.None) 118 monitor = new object(); 119 this.mode = mode; 120 } 121 122 // Don't trigger expensive initialization 123 [DebuggerBrowsable(DebuggerBrowsableState.Never)] 124 public T Value 125 { 126 get 127 { 128 if (inited) 129 return value; 130 if (exception != null) 131 throw exception; 132 133 return InitValue(); 134 } 135 } 136 137 public bool IsValueCreated 138 { 139 get { return inited; } 140 } 141 142 private T InitValue() 143 { 144 switch (mode) 145 { 146 case LazyThreadSafetyMode.None: 147 { 148 var init_factory = factory; 149 if (init_factory == null) 150 throw exception = 151 new InvalidOperationException( 152 "The initialization function tries to access Value on this instance"); 153 try 154 { 155 factory = null; 156 T v = init_factory(); 157 value = v; 158 Thread.MemoryBarrier(); 159 inited = true; 160 } 161 catch (Exception ex) 162 { 163 exception = ex; 164 throw; 165 } 166 break; 167 } 168 case LazyThreadSafetyMode.PublicationOnly: 169 { 170 var init_factory = factory; 171 T v; 172 173 //exceptions are ignored 174 v = init_factory != null ? init_factory() : default(T); 175 176 lock (monitor) 177 { 178 if (inited) 179 return value; 180 value = v; 181 Thread.MemoryBarrier(); 182 inited = true; 183 factory = null; 184 } 185 break; 186 } 187 case LazyThreadSafetyMode.ExecutionAndPublication: 188 { 189 lock (monitor) 190 { 191 if (inited) 192 return value; 193 194 if (factory == null) 195 throw exception = 196 new InvalidOperationException( 197 "The initialization function tries to access Value on this instance"); 198 199 var init_factory = factory; 200 try 201 { 202 factory = null; 203 T v = init_factory(); 204 value = v; 205 Thread.MemoryBarrier(); 206 inited = true; 207 } 208 catch (Exception ex) 209 { 210 exception = ex; 211 throw; 212 } 213 } 214 break; 215 } 216 default: 217 throw new InvalidOperationException("Invalid LazyThreadSafetyMode " + mode); 218 } 219 220 if (monitor == null) 221 { 222 value = factory(); 223 inited = true; 224 } 225 else 226 { 227 lock (monitor) 228 { 229 if (inited) 230 return value; 231 232 if (factory == null) 233 throw new InvalidOperationException( 234 "The initialization function tries to access Value on this instance"); 235 236 var init_factory = factory; 237 try 238 { 239 factory = null; 240 T v = init_factory(); 241 value = v; 242 Thread.MemoryBarrier(); 243 inited = true; 244 } 245 catch 246 { 247 factory = init_factory; 248 throw; 249 } 250 } 251 } 252 253 return value; 254 } 255 256 public override string ToString() 257 { 258 if (inited) 259 return value.ToString(); 260 else 261 return "Value is not created"; 262 } 263 } 264}