[你必須知道的.NET]第三十三回,深入.NET 4.0之,Lazy<T>點滴
釋出日期:2009.10.29 作者:Anytao
© 2009 Anytao.com ,Anytao原創作品,轉貼請註明作者和出處。
物件的建立方式,始終代表了軟體工業的生產力方向,代表了先進軟體技術發展的方向,也代表了廣大程式開發者的集體智慧。以new的方式建立,通過工廠方法,利用IoC容器,都以不同的方式實現了活生生例項成員的創生。而本文所關注的Lazy<T>也是幹這事兒的。不過,簡單說來,Lazy<T>要實現的就是按“需”建立,而不是按時建立。
我們往往有這樣的情景,一個關聯物件的建立需要較大的開銷,為了避免在每次執行時建立這種傢伙,有一種聰明的辦法叫做實現“懶物件”,或者延遲載入。.NET 4.0之前,實現懶物件的機制,需要開發者自己來實現與管理,例如,你可以翻開老趙同志的
[Serializable] public class Lazy<T> { public Lazy(); public Lazy(bool isThreadSafe); public Lazy(Func<T> valueFactory); public Lazy(Func<T> valueFactory, bool isThreadSafe); public boolIsValueCreated { get; } public T Value { get; } public override string ToString(); }
注:VS2010 Beta2對Lazy<T>和VS2010 Beta1有較大差異,因此本文僅以最新版本為標準,並不保證最終.NET 4.0正式版的實際情況。
假設,我們有一個大塊頭:
public class Big { public int ID { get; set; } // Other resources }
那麼,可以使用如下的方式來實現Big的延遲建立:
static void Main(string[] args) { Lazy<Big> lazyBig = new Lazy<Big>(); }
從Lazy<T>的定義可知,其Value屬性就是我們包裝在Lazy Wrapper中的真實Big物件,那麼當我們第一次訪問lazyBig.Value時,就回自動的建立Big例項。
static void Main(string[] args) { Lazy<Big> lazyBig = new Lazy<Big>(); Console.WriteLine(lazyBig.Value.ID); }
當然,有其定義可知,Lazy遠沒有這麼小兒科,它同時還可以為我們提供以下的服務:
- 通過IsValueCreated,獲取是否“已經”建立了例項物件。
- 解決非預設建構函式問題。
顯而易見。我們的Big類並沒有提供帶引數建構函式,那麼如下的Big類:
public class Big { public Big(int id) { this.ID = id; } public int ID { get; set; } // Other resources }
上述建立方式將引發執行時異常,提示包裝物件沒有無參的建構函式。那麼,這種情形下的延遲載入,該如何應對呢?其實Lazy<T>的構造中還包括:
public Lazy(Func<T> valueFactory);
它正是用來應對這樣的挑戰:
static void Main(string[] args) { // Lazy<Big> lazyBig = new Lazy<Big>(); Lazy<Big> lazyBig = new Lazy<Big>(() => new Big(100)); Console.WriteLine(lazyBig.Value.ID); }
其實,從public Lazy(Func<T> valueFactory)的定義可知,valueFactory可以返回任意的T例項,那麼任何複雜的建構函式,物件工廠或者IoC容器方式都可以在此以輕鬆的方式相容,例如:
public class BigFactory { public static Big Build() { return new Big(100); } }
可以應用Lazy<T>和BigFactory實現Big的延遲載入:
static void Main(string[] args) { Lazy<Big> lazyBig = new Lazy<Big>(() => BigFactory.Build()); Console.WriteLine(lazyBig.Value.ID); }
- 提供多執行緒環境支援。
另外的構造器:
public Lazy(bool isThreadSafe); public Lazy(Func<T> valueFactory, bool isThreadSafe);
中,isThreadSafe則應用於多執行緒環境下,如果isThreadSafe為false,那麼延遲載入物件則一次只能創建於一個執行緒。
關於Lazy<T>的應用,其實已經不是一個純粹的語言問題,還涉及了對設計的考量,例如實現整個物件的延遲載入,或者實現延遲屬性,考量執行緒安全等等。既然是點滴,就不說教太多。因為,.NET 4.0提供的關注度實在不少,我們眼花繚亂了。
參考文獻
- Lazy Initialization, http://msdn.microsoft.com/en-us/library/dd997286(VS.100).aspx
更多閒言碎語,關注anytao.net