语言和模式互相促进,语言让模式实现有更多可能性,越来越多优秀的被语言实现.模式实现的责任从开发者转移到语言.延迟初始化(Lazyinitialization)已经在.Net 4.0中给出了默认实现.本文将探究其使用方法和实现.
为什么要延迟初始化(Lazy initialization)?
平时开发能接触到延迟初始化可能是在两个地方,一个是单件模式Singletonpattern,一个是Nhibernate;这两个典型场景很能说明为什么需要延迟初始化:
1.需要初始化的对象属于昂贵的资源,直到使用的时候再初始化load-on-demand
2.初始化过程本身相当复杂,代码中要避免这种无谓复杂性,直到使用再初始化
更多延迟初始化的资料,请点击这里;
.Net 4.0 Lazy实现Lazy initialization
.Net 4.0中的延迟初始化的默认实现时Lazy,我们通过一个简单的例子看一下怎么使用,为了方便讨论我们新建一个Student的实体类:
public class Student { public int ID { get;set; } public string Name { get; set; } } 延迟初始化Student:
Lazy student = newLazy(); Console.WriteLine(student); student.Value.ID = 23; student.Value.Name = "New"; Console.WriteLine(student); 我们在Console.WriteLine(student); 一行设置断点查看,发现IsValueCreated是false ,Value值是null,截图如下:
继续往下走,在student.Value.ID = 23;赋值的时候,再次查看student对象的值,IsValueCreated为true,Value已经不为空,见下图.
我们可以猜想,应该是在Value的Get方法中对对象进行了实例化,打开Reflector v6验证:
Lazy
1 [Serializable, DebuggerDisplay("ThreadSafetyMode={Mode}, IsValueCreated={IsValueCreated}, IsValueFaulted={IsValueFaulted}, Value={ValueForDebugDisplay}"), DebuggerTypeProxy(typeof(System_LazyDebugView<>)), ComVisible(false), HostProtection(SecurityAction.LinkDemand, Synchronization=true, ExternalThreading=true)] 2 public class Lazy 3 { 4 // Fields 5 private volatile object m_boxed; 6 [NonSerialized] 7 private readonly object m_threadSafeObj; 8 [NonSerialized] 9 private Func m_valueFactory; 10 private static Func PUBLICATION_ONLY_OR_ALREADY_INITIALIZED; 11 12 // Methods 13 static Lazy() 14 { 15 Lazy.PUBLICATION_ONLY_OR_ALREADY_INITIALIZED = delegate { 16 return default(T); 17 }; 18 } 19 20 [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] 21 public Lazy() : this(LazyThreadSafetyMode.ExecutionAndPublication) 22 { 23 } 24 25 public Lazy(bool isThreadSafe) : this(isThreadSafe ? LazyThreadSafetyMode.ExecutionAndPublication : LazyThreadSafetyMode.None) 26 { 27 } 28 29 [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] 30 public Lazy(Func valueFactory) : this(valueFactory, LazyThreadSafetyMode.ExecutionAndPublication) 31 { 32 } 33 34 public Lazy(LazyThreadSafetyMode mode) 35 { 36 this.m_threadSafeObj = Lazy.GetObjectFromMode(mode); 37 } 38 39 public Lazy(Func valueFactory, bool isThreadSafe) : this(valueFactory, isThreadSafe ? LazyThreadSafetyMode.ExecutionAndPublication : LazyThreadSafetyMode.None) 40 { 41 } 42 43 public Lazy(Func valueFactory, LazyThreadSafetyMode mode) 44 { 45 if (valueFactory == null) 46 { 47 throw new ArgumentNullException("valueFactory"); 48 } 49 this.m_threadSafeObj = Lazy.GetObjectFromMode(mode); 50 this.m_valueFactory = valueFactory; 51 } 52 53 private Boxed CreateValue() 54 { 55 Boxed boxed = null; 56 LazyThreadSafetyMode mode = this.Mode; 57 if (this.m_valueFactory != null) 58 { 59 try 60 { 61 if ((mode != LazyThreadSafetyMode.PublicationOnly) && (this.m_valueFactory == Lazy.PUBLICATION_ONLY_OR_ALREADY_INITIALIZED)) 62 { 63 throw new InvalidOperationException(Environment.GetResourceString("Lazy_Value_RecursiveCallsToValue")); 64 } 65 Func valueFactory = this.m_valueFactory; 66 if (mode != LazyThreadSafetyMode.PublicationOnly) 67 { 68 this.m_valueFactory = Lazy.PUBLICATION_ONLY_OR_ALREADY_INITIALIZED; 69 } 70 return new Boxed(valueFactory()); 71 } 72 catch (Exception exception) 73 { 74 if (mode != LazyThreadSafetyMode.PublicationOnly) 75 { 76 this.m_boxed = new LazyInternalExceptionHolder(exception.PrepForRemoting()); 77 } 78 throw; 79 } 80 } 81 try 82 { 83 boxed = new Boxed((T) Activator.CreateInstance(typeof(T))); 84 } 85 catch (MissingMethodException) 86 { 87 Exception ex = new MissingMemberException(Environment.GetResourceString("Lazy_CreateValue_NoParameterlessCtorForT")); 88 if (mode != LazyThreadSafetyMode.PublicationOnly) 89 { 90 this.m_boxed = new LazyInternalExceptionHolder(ex); 91 } 92 throw ex; 93 } 94 return boxed; 95 } 96 97 private static object GetObjectFromMode(LazyThreadSafetyMode mode) 98 { 99 if (mode == LazyThreadSafetyMode.ExecutionAndPublication)100 {101 return new object();102 }103 if (mode == LazyThreadSafetyMode.PublicationOnly)104 {105 return Lazy.PUBLICATION_ONLY_OR_ALREADY_INITIALIZED;106 }107 if (mode != LazyThreadSafetyMode.None)108 {109 throw new ArgumentOutOfRangeException("mode", Environment.GetResourceString("Lazy_ctor_ModeInvalid"));110 }111 return null;112 }113 114 private T LazyInitValue()115 {116 Boxed boxed = null;117 switch (this.Mode)118 {119 case LazyThreadSafetyMode.None:120 boxed = this.CreateValue();121 this.m_boxed = boxed;122 break;123 124 case LazyThreadSafetyMode.PublicationOnly:125 boxed = this.CreateValue();126 if (Interlocked.CompareExchange(ref this.m_boxed, boxed, null) != null)127 {128 boxed = (Boxed) this.m_boxed;129 }130 break;131 132 default:133 {134 object obj2;135 bool lockTaken = false;136 try137 {138 Monitor.Enter(obj2 = this.m_threadSafeObj, ref lockTaken);139 if (this.m_boxed == null)140 {141 boxed = this.CreateValue();142 this.m_boxed = boxed;143 }144 else145 {146 boxed = this.m_boxed as Boxed;147 if (boxed == null)148 {149 LazyInternalExceptionHolder holder = this.m_boxed as LazyInternalExceptionHolder;150 throw holder.m_exception;151 }152 }153 }154 finally155 {156 if (lockTaken)157 {158 Monitor.Exit(obj2);159 }160 }161 break;162 }163 }164 return boxed.m_value;165 }166 167 [OnSerializing]168 private void OnSerializing(StreamingContext context)169 {170 T local1 = this.Value;171 }172 173 public override string ToString()174 {175 if (!this.IsValueCreated)176 {177 return Environment.GetResourceString("Lazy_ToString_ValueNotCreated");178 }179 return this.Value.ToString();180 }181 182 // Properties183 public bool IsValueCreated184 {185 [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]186 get187 {188 return ((this.m_boxed != null) && (this.m_boxed is Boxed));189 }190 }191 192 internal bool IsValueFaulted193 {194 get195 {196 return (this.m_boxed is LazyInternalExceptionHolder);197 }198 }199 200 internal LazyThreadSafetyMode Mode201 {202 get203 {204 if (this.m_threadSafeObj == null)205 {206 return LazyThreadSafetyMode.None;207 }208 if (this.m_threadSafeObj == Lazy.PUBLICATION_ONLY_OR_ALREADY_INITIALIZED)209 {210 return LazyThreadSafetyMode.PublicationOnly;211 }212 return LazyThreadSafetyMode.ExecutionAndPublication;213 }214 }215 216 [DebuggerBrowsable(DebuggerBrowsableState.Never)]217 public T Value218 {219 get220 {221 Boxed boxed = null;222 if (this.m_boxed != null)223 {224 boxed = this.m_boxed as Boxed;225 if (boxed != null)226 {227 return boxed.m_value;228 }229 LazyInternal< type="text/javascript">< type="text/javascript">< type="text/javascript">< type="text/javascript">< type="text/javascript">ExceptionHolder holder = this.m_boxed as LazyInternalExceptionHolder;230 throw holder.m_exception;231 }232 Debugger.NotifyOfCrossThreadDependency();233 return this.LazyInitValue();234 }235 }236 237 internal T ValueForDebugDisplay238 {239 get240 {241 if (!this.IsValueCreated)242 {243 return default(T);244 }245 return ((Boxed) this.m_boxed).m_value;246 }247 }248 249 // Nested Types250 [Serializable]251 private class Boxed252 {253 // Fields254 internal T m_value;255 256 // Methods257 [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]258 internal Boxed(T value)259 {260 this.m_value = value;261 }262 }263 264 private class LazyInternalExceptionHolder265 {266 // Fields267 internal Exception m_exception;268 269 // Methods270 [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]271 internal LazyInternalExceptionHolder(Exception ex)272 {273 this.m_exception = ex;274 }275 }276 }277 278 是不是和我们想的一样呢?
为了更清晰的看出延迟加载的处理逻辑,我按照这个代码的实现思路,去掉复杂应用场景中队异常,多线程等方面的代码,重新实现了一个Lazy,就叫它YaLazy吧
1 public class YaLazy 2 { 3 private bool _isValueCreated = false; 4 public bool IsValueCreated 5 { 6 get 7 { 8 return _isValueCreated; 9 }10 }11 private T _value;12 public T Value13 {14 get15 {16 if (this._value != null)17 {18 return (T)_value;19 }20 return CreateValue();21 22 }23 }24 private T CreateValue()25 {26 _isValueCreated = true;27 _value = (T)Activator.CreateInstance(typeof(T));28 return _value;29 }30 }使用方法和Lazy类似:
1 YaLazy student2 = new YaLazy();2 Console.WriteLine(student2);3 student2.Value.ID = 23;4 student2.Value.Name = "New";5 Console.WriteLine(student2);6 建议单步调试~
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/12639172/viewspace-663801/
,如需转载,请注明出处,否则将追究法律责任。