1. 程式人生 > >解密Lazy<T>

解密Lazy<T>

number ima 理解 ica this class 實例 初始 code

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>