解密Lazy<T>
1.Lazy<T>的使用
無意間看到一段代碼,在創建對象的時候使用了Lazy,顧名思義Lazy肯定是延遲加載,那麽它具體是如何創建對象,什麽時候創建對象了? 先看這段示列代碼:
public class OrderController : Controller { private readonly Lazy<OrderService> _orderSrv = new Lazy<OrderService>(); public ActionResult CreateOrder(OrderModel model) {var result = _orderSrv.Value.CreateOrder(model); return Json(result); } }
使用非常簡單,把 OrderService 放到Lazy<T> 中,然後 _orderSrv.Value 的時候才真正創建OrderService 對象。
那麽問題來,是不是每次_orderSrv.Value 一下,就創建一個對象了? 想到這裏,程序猿基本的條件反射,對著Lazy按下F12。
構造函數中,有個isThreadSafe的參數,默認是true。ok,參考了msdn的例子,我們來測試看看。
static void Main(string[] args) { Lazy<int> number = new Lazy<int>(() => Thread.CurrentThread.ManagedThreadId); Thread t1 = new Thread(() => Console.WriteLine("number on t1 = {0} ThreadID = {1}"
,number.Value, Thread.CurrentThread.ManagedThreadId)); t1.Start(); Thread t2= new Thread(() => Console.WriteLine("number on t2 = {0} ThreadID = {1}"
,number.Value, Thread.CurrentThread.ManagedThreadId)); t2.Start(); Thread t3 = new Thread(() => Console.WriteLine("number on t3 = {0} ThreadID = {1}"
, number.Value,Thread.CurrentThread.ManagedThreadId)); t3.Start(); Console.ReadLine(); }
結果:
很明顯,number 被ID=10的線程初始化後,值一直沒有改變,說明三個線程用的是同一個實例。
再試試 isThreadSafe=false 。
Lazy<int> number = new Lazy<int>(() => Thread.CurrentThread.ManagedThreadId, false);
結果(1):
number實例被ID=11的線程使用後,其他線程就不能再正確使用了,number.value=0 說明 int並沒有被。
結果(2):
直接報錯了,我的理解是,Lazy此時並不支持多線程並發。
2.Lazy<T> 的 valueFactory
繼續在f12中找到解釋:
結合我們上面的例子,可分析出,valueFactory是個委托,number.value的時候就是由valueFactory來創建這個實例。
看到這裏,我們發現Lazy<T> 還是很強大的,可以用T的默認構造函數來創建實例也可以用指定的Func來創建實例,而且還支持多線程安全。
3.Lazy<T>的工作原理
用反編譯插件看看代碼:
static Lazy() { Lazy<T>.ALREADY_INVOKED_SENTINEL = () => default(T); Lazy<T>.PUBLICATION_ONLY_SENTINEL = new object(); }
[__DynamicallyInvokable] public Lazy(Func<T> valueFactory, LazyThreadSafetyMode mode) { if (valueFactory == null) { throw new ArgumentNullException("valueFactory"); } this.m_threadSafeObj = Lazy<T>.GetObjectFromMode(mode); this.m_valueFactory = valueFactory; }
看到 default(T) 和 this.m_valueFactory = valueFactory 大概也知道是如何創建實例了吧。
解密Lazy<T>