当前位置 : 主页 > 编程语言 > 其它开发 >

.Net 4.0 延迟初始化:Lazy<T>

来源:互联网 收集:自由互联 发布时间:2022-05-26
.Net 4.0 延迟初始化:LazyT 语言和模式互相促进,语言让模式实现有更多可能性,越来越多优秀的被语言实现.模式实现的责任从开发者转移到语言.延迟初始化(Lazyinitialization)已经在.Net 4.0中给
.Net 4.0 延迟初始化:Lazy<T> 语言和模式互相促进,语言让模式实现有更多可能性,越来越多优秀的被语言实现.模式实现的责任从开发者转移到语言.延迟初始化(Lazyinitialization)已经在.Net 4.0中给出了默认实现.本文将探究其使用方法和实现方式.

 昨天我们说了一个.Net 4.0里面StringBuilder新增的Clear()方法及其实现,非常简单.今天要说的就稍微复杂一点了.

       语言和模式互相促进,语言让模式实现有更多可能性,越来越多优秀的被语言实现.模式实现的责任从开发者转移到语言.延迟初始化(Lazyinitialization)已经在.Net 4.0中给出了默认实现.本文将探究其使用方法和实现.

  为什么要延迟初始化(Lazy initialization)?

    平时开发能接触到延迟初始化可能是在两个地方,一个是单件模式Singletonpattern,一个是Nhibernate;这两个典型场景很能说明为什么需要延迟初始化:

1.需要初始化的对象属于昂贵的资源,直到使用的时候再初始化load-on-demand

2.初始化过程本身相当复杂,代码中要避免这种无谓复杂性,直到使用再初始化

更多延迟初始化的资料,请点击这里;

 

.Net 4.0 Lazy<T>实现Lazy initialization

        .Net 4.0中的延迟初始化的默认实现时Lazy<T>,我们通过一个简单的例子看一下怎么使用,为了方便讨论我们新建一个Student的实体类:

 

    public class Student
{
public int ID
{
get;set;
}
public string Name
{
get; set;
}
}

 

延迟初始化Student:

 

  Lazy<Student> student = newLazy<Student>();
Console.WriteLine(student);
student.Value.ID
= 23;
student.Value.Name
= "New";
Console.WriteLine(student);

 

  我们在Console.WriteLine(student);  一行设置断点查看,发现IsValueCreated是false ,Value值是null,截图如下:

 

 lazy1

继续往下走,在student.Value.ID = 23;赋值的时候,再次查看student对象的值,IsValueCreated为true,Value已经不为空,见下图.

 lazy2  

我们可以猜想,应该是在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<T>
3 {
4 // Fields
5   private volatile object m_boxed;
6 [NonSerialized]
7 private readonly object m_threadSafeObj;
8 [NonSerialized]
9 private Func<T> m_valueFactory;
10 private static Func<T> PUBLICATION_ONLY_OR_ALREADY_INITIALIZED;
11
12 // Methods
13   static Lazy()
14 {
15 Lazy<T>.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<T> valueFactory) : this(valueFactory, LazyThreadSafetyMode.ExecutionAndPublication)
31 {
32 }
33
34 public Lazy(LazyThreadSafetyMode mode)
35 {
36 this.m_threadSafeObj = Lazy<T>.GetObjectFromMode(mode);
37 }
38
39 public Lazy(Func<T> valueFactory, bool isThreadSafe) : this(valueFactory, isThreadSafe ? LazyThreadSafetyMode.ExecutionAndPublication : LazyThreadSafetyMode.None)
40 {
41 }
42
43 public Lazy(Func<T> valueFactory, LazyThreadSafetyMode mode)
44 {
45 if (valueFactory == null)
46 {
47 throw new ArgumentNullException("valueFactory");
48 }
49 this.m_threadSafeObj = Lazy<T>.GetObjectFromMode(mode);
50 this.m_valueFactory = valueFactory;
51 }
52
53 private Boxed<T> CreateValue()
54 {
55 Boxed<T> 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<T>.PUBLICATION_ONLY_OR_ALREADY_INITIALIZED))
62 {
63 throw new InvalidOperationException(Environment.GetResourceString("Lazy_Value_RecursiveCallsToValue"));
64 }
65 Func<T> valueFactory = this.m_valueFactory;
66 if (mode != LazyThreadSafetyMode.PublicationOnly)
67 {
68 this.m_valueFactory = Lazy<T>.PUBLICATION_ONLY_OR_ALREADY_INITIALIZED;
69 }
70 return new Boxed<T>(valueFactory());
71 }
72 catch (Exception exception)
73 {
74 if (mode != LazyThreadSafetyMode.PublicationOnly)
75 {
76 this.m_boxed = new LazyInternalExceptionHolder<T>(exception.PrepForRemoting());
77 }
78 throw;
79 }
80 }
81 try
82 {
83 boxed = new Boxed<T>((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<T>(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<T>.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<T> 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<T>) this.m_boxed;
129 }
130 break;
131
132 default:
133 {
134 object obj2;
135 bool lockTaken = false;
136 try
137 {
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 else
145 {
146 boxed = this.m_boxed as Boxed<T>;
147 if (boxed == null)
148 {
149 LazyInternalExceptionHolder<T> holder = this.m_boxed as LazyInternalExceptionHolder<T>;
150 throw holder.m_exception;
151 }
152 }
153 }
154 finally
155 {
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 // Properties
183   public bool IsValueCreated
184 {
185 [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
186 get
187 {
188 return ((this.m_boxed != null) && (this.m_boxed is Boxed<T>));
189 }
190 }
191
192 internal bool IsValueFaulted
193 {
194 get
195 {
196 return (this.m_boxed is LazyInternalExceptionHolder<T>);
197 }
198 }
199
200 internal LazyThreadSafetyMode Mode
201 {
202 get
203 {
204 if (this.m_threadSafeObj == null)
205 {
206 return LazyThreadSafetyMode.None;
207 }
208 if (this.m_threadSafeObj == Lazy<T>.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 Value
218 {
219 get
220 {
221 Boxed<T> boxed = null;
222 if (this.m_boxed != null)
223 {
224 boxed = this.m_boxed as Boxed<T>;
225 if (boxed != null)
226 {
227 return boxed.m_value;
228 }
229 LazyInternalExceptionHolder<T> holder = this.m_boxed as LazyInternalExceptionHolder<T>;
230 throw holder.m_exception;
231 }
232 Debugger.NotifyOfCrossThreadDependency();
233 return this.LazyInitValue();
234 }
235 }
236
237 internal T ValueForDebugDisplay
238 {
239 get
240 {
241 if (!this.IsValueCreated)
242 {
243 return default(T);
244 }
245 return ((Boxed<T>) this.m_boxed).m_value;
246 }
247 }
248
249 // Nested Types
250   [Serializable]
251 private class Boxed
252 {
253 // Fields
254   internal T m_value;
255
256 // Methods
257   [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 LazyInternalExceptionHolder
265 {
266 // Fields
267   internal Exception m_exception;
268
269 // Methods
270   [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<T>,就叫它YaLazy<T>吧

 

 1  public class YaLazy<T>
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 Value
13 {
14 get
15 {
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<T>类似:

1             YaLazy<Student> student2 = new YaLazy<Student>();
2 Console.WriteLine(student2);
3 student2.Value.ID = 23;
4 student2.Value.Name = "New";
5 Console.WriteLine(student2);
6  

 

 建议单步调试~


Share |

 

坚强2002和你一起回头再说... read my mind!

网友评论