天天看點

懶人懶類懶方法 - 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,如需轉載請自行聯系原作者