• 解密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 大概也知道是如何创建实例了吧。

     本文博客园地址:http://www.cnblogs.com/struggle999/p/6917067.html 

  • 相关阅读:
    shell脚本积累
    while,shift,until,case
    条件测试命令,if命令,双圆括号,双中括号
    seq命令,tr命令,sort命令,cut命令
    正则,grep命令详解
    Ansible实现批量管理服务器
    实时同步服务知识梳理
    RHEL7破解密码操作步骤
    运维核心基础知识之——MD5sum校验文件
    Linux运维基础提高之RAID卡和磁盘分区
  • 原文地址:https://www.cnblogs.com/struggle999/p/6917067.html
Copyright © 2020-2023  润新知