首页 > 代码库 > 解密Lazy<T>

解密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=http://www.mamicode.com/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>