文章目錄
anytao.net | 《你必須知道的.NET》網站 | Anytao技術部落格
發布日期:2009.10.29 作者:Anytao
2009 Anytao.com ,Anytao原創作品,轉貼請註明作者和出處。
對象的建立方式,始終代表了軟體工業的生產力方向,代表了先進軟體技術發展的方向,也代表了廣大程式開發人員的集體智慧。以new的方式建立,通過Factory 方法,利用IoC容器,都以不同的方式實現了活生生執行個體成員的創生。而本文所關注的Lazy<T>也是幹這事兒的。不過,簡單說來,Lazy<T>要實現的就是按“需”建立,而不是按時建立。
我們往往有這樣的情景,一個關聯對象的建立需要較大的開銷,為了避免在每次運行時建立這種傢伙,有一種聰明的辦法叫做實現“懶對象”,或者消極式載入。.NET 4.0之前,實現懶對象的機制,需要開發人員自己來實現與管理,例如,你可以翻開老趙同志的較為理想的延遲代理的編寫方式一文來瞭解其原理和場合。可喜的是,在.NET 4.0中包含的另一個好玩的傢伙System.Lazy<T>。它的定義如下:
[Serializable]public class Lazy<T>{ public Lazy(); public Lazy(bool isThreadSafe); public Lazy(Func<T> valueFactory); public Lazy(Func<T> valueFactory, bool isThreadSafe); public bool IsValueCreated { 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
anytao | 2009 Anytao.com
2009/10/29 | http://anytao.cnblogs.com/ | http://www.anytao.net/blog/post/2009/10/28/anytao-insidenet-33-about-lazy.aspx
本文以“現狀”提供且沒有任何擔保,同時也沒有授予任何權利。 | This posting is provided "AS IS" with no warranties, and confers no rights.
本文著作權歸作者所有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文串連,否則保留追究法律責任的權利。