天天看点

懒人懒类懒方法 - System.Lazy<T>

 我这个技术博客被冷落了近1年之后,我觉得不能再这样下去,至少应该平均2周发一篇博文。坚持了两三篇博文之后,我觉得今天是应该写点什么了,却发现这段时间以来似乎没什么值得摆出来的,仔细回想了一遍,大概就只有Lazy<T>还有点意思,可以写写。

  Lazy<T>,正如其名,是为懒人设计的一个懒加载处理类。所谓懒加载,最简单的实现就是事先申明变量,但在实际使用的时候才创建对象实例。比如,通常会这么写一个懒加载的属性:

1

2

3

4

5

6

<code>private</code> <code>IList&lt;</code><code>string</code><code>&gt; names;</code>

<code>public</code> <code>IList&lt;</code><code>string</code><code>&gt; {</code>

<code>    </code><code>get</code> <code>{</code>

<code>        </code><code>return</code> <code>names ?? (names == </code><code>new</code> <code>List&lt;</code><code>string</code><code>&gt;());</code>

<code>    </code><code>}</code>

<code>}</code>

  懒加载比较典型的例子就是实现Singleton模式了。简单的Singleton通常会这样写:

7

8

9

<code>public</code> <code>class</code> <code>Singleton1</code>

<code>{</code>

<code>    </code><code>private</code> <code>static</code> <code>Singleton1 instance;</code>

<code>    </code><code>public</code> <code>static</code> <code>Singleton1 Default</code>

<code>    </code><code>{</code>

<code>        </code><code>get</code> <code>{ </code><code>return</code> <code>instance ?? (instance = </code><code>new</code> <code>Singleton1()); }</code>

<code>    </code><code>private</code> <code>Singleton1() { }</code>

  改写成Lazy&lt;T&gt;实现

<code>public</code> <code>class</code> <code>Singleton2</code>

<code>    </code><code>private</code> <code>static</code> <code>readonly</code> <code>Lazy&lt;Singleton2&gt; lazyInstance</code>

<code>            </code><code>= </code><code>new</code> <code>Lazy&lt;Singleton2&gt;();</code>

<code>    </code><code>public</code> <code>static</code> <code>Singleton2 Default</code>

<code>        </code><code>get</code> <code>{ </code><code>return</code> <code>lazyInstance.Value; }</code>

  不过上面这个例子不是真正的单例,使用Lazy&lt;T&gt;的默认构造产生懒加载实例,需要T类型有公共的默认构造,否则在运行时会抛出 System.MissingMemberException。所以单例里其实应该用

<code>Lazy&lt;T&gt;(Func&lt;T&gt;)</code>

  所以再改写

10

11

12

13

14

<code>public</code> <code>class</code> <code>Singleton3</code>

<code>    </code><code>private</code> <code>static</code> <code>readonly</code> <code>Lazy&lt;Singleton3&gt; lazyInstance</code>

<code>            </code><code>= </code><code>new</code> <code>Lazy&lt;Singleton3&gt;(Create);</code>

<code>    </code><code>public</code> <code>static</code> <code>Singleton3 Default</code>

<code>    </code><code>private</code> <code>static</code> <code>Singleton3 Create()</code>

<code>        </code><code>return</code> <code>new</code> <code>Singleton3();</code>

<code>    </code><code>private</code> <code>Singleton3() { }</code>

  这么看来,Lazy&lt;T&gt;实现的代码貌似更多,没能偷到懒……不过,如果要求线程安全的Singleton呢,一般会这么实现:

15

16

17

18

19

20

21

22

23

<code>public</code> <code>class</code> <code>Singleton4</code>

<code>    </code><code>private</code> <code>static</code> <code>Singleton4 instance;</code>

<code>    </code><code>private</code> <code>static</code> <code>readonly</code> <code>object</code> <code>locker = </code><code>new</code> <code>object</code><code>();</code>

<code>    </code><code>public</code> <code>static</code> <code>Singleton4 Default</code>

<code>        </code><code>get</code>

<code>        </code><code>{</code>

<code>            </code><code>if</code> <code>(instance == </code><code>null</code><code>)</code>

<code>            </code><code>{</code>

<code>                </code><code>lock</code> <code>(locker)</code>

<code>                </code><code>{</code>

<code>                    </code><code>if</code> <code>(instance == </code><code>null</code><code>)</code>

<code>                    </code><code>{</code>

<code>                        </code><code>instance = </code><code>new</code> <code>Singleton4();</code>

<code>                    </code><code>}</code>

<code>                </code><code>}</code>

<code>            </code><code>}</code>

<code>            </code><code>return</code> <code>instance;</code>

<code>        </code><code>}</code>

<code>    </code><code>private</code> <code>Singleton4() { }</code>

  这段代码,又是锁又是判断的,光“instance == null”就判断了两次,为什么?想不明白就Google,再搞不懂就看个没这么复杂的实现

<code>public</code> <code>class</code> <code>Singleton5</code>

<code>    </code><code>private</code> <code>static</code> <code>readonly</code> <code>Lazy&lt;Singleton5&gt; lazyInstance</code>

<code>            </code><code>= </code><code>new</code> <code>Lazy&lt;Singleton5&gt;(Create, </code><code>true</code><code>);</code>

<code>    </code><code>public</code> <code>static</code> <code>Singleton5 Default</code>

<code>    </code><code>private</code> <code>static</code> <code>Singleton5 Create()</code>

<code>        </code><code>return</code> <code>new</code> <code>Singleton5();</code>

<code>    </code><code>private</code> <code>Singleton5() { }</code>

  还要说明的一点是,懒加载当然不只是为了Singleton而设计的,就拿本文中的第一个例子来说,它有可能会有更复杂也更实际一点的实现(需要的时候再从数据库去获取数据):

<code>class</code> <code>Blabla</code>

<code>    </code><code>private</code> <code>readonly</code> <code>Lazy&lt;IList&lt;</code><code>string</code><code>&gt;&gt; lazyNames;</code>

<code>    </code><code>public</code> <code>Blabla()</code>

<code>        </code><code>lazyNames = </code><code>new</code> <code>Lazy&lt;IList&lt;</code><code>string</code><code>&gt;&gt;(GetNameList);</code>

<code>    </code><code>private</code> <code>IList&lt;</code><code>string</code><code>&gt; GetNameList()</code>

<code>        </code><code>DataTable data = dbHelper.getUsers();</code>

<code>        </code><code>List&lt;</code><code>string</code><code>&gt; names = </code><code>new</code> <code>List&lt;</code><code>string</code><code>&gt;();</code>

<code>        </code><code>foreach</code> <code>(DataRow row </code><code>in</code> <code>data.Rows)</code>

<code>            </code><code>names.Add(row[</code><code>"name"</code><code>].ToString());</code>

<code>        </code><code>return</code> <code>names;</code>

<code>    </code><code>public</code> <code>IList&lt;</code><code>string</code><code>&gt; Names</code>

<code>        </code><code>get</code> <code>{ </code><code>return</code> <code>lazyNames.Value; }</code>

  本文转自边城__ 51CTO博客,原文链接:http://blog.51cto.com/jamesfancy/1365402,如需转载请自行联系原作者