• 延迟初始化


    概念:一个对象的延迟初始化(也称延迟实例化)意味着该对象的创建将会延迟至第一次使用该对象时。 延迟初始化主要用于提高性能,避免浪费计算,并减少程序内存要求。

    以下是最常见的方案:

      • 有一个对象的创建开销很大时,应用程序可能不会使用它。 例如,假定您在内存中有一个 Customer 对象,该对象的 Orders 属性返回一个 Orders 对象。 初始化 Orders 对象可能需要创建 Orders 对象的一个大数组(Orders[]),并可能需要数据库连接。 如果用户从不访问 Orders 属性,则没有理由使用系统内存或计算周期来创建 Orders 对象。 通过使用 Lazy<Orders> 将 Orders 对象声明为延迟初始化,可以避免在不使用该对象的情况下浪费系统资源。

      • 有一个对象的创建开销很大,您想要将创建它的时间延迟到完成其他开销大的操作之后。 例如,假定您的应用程序在启动时加载若干个对象实例,但只有一些对象实例需要立即执行。 通过将不必要的对象的初始化延迟到已创建必要的对象之后,可以提高应用程序的启动性能。

        尽管您可以编写自己的代码来执行迟缓初始化,但我们建议改用 System..::.Lazy<(Of <(T>)>) 类。 Lazy<(Of <(T>)>) 支持线程安全(在一个线程中创建实例后,对其它线也是共享的),并提供一致的异常传播策略。

        基本语法:

        1 Lazy<Orders> Orders=new Lazy<Orders>();

        另外,还可以在 Lazy<(Of <(T>)>) 构造函数中传递一个委托,用于在创建时调用包装类的特定构造函数重载,并执行所需的任何其他初始化步骤,如以下示例中所示。

        1 Lazy<Orders> _orders = new Lazy<Orders>(() => new Orders(OrderSorted.CreateDate)); //可以重载指定的构造函数,如用来实现一种排序规则

        在创建 Lazy 对象之后,在第一次访问 Lazy<(Of <(T>)>) 实例的 Value 属性之前,将不会创建 Orders 的实例。 在第一次访问包装类型时,将会创建并返回该包装类型,并将其存储起来以备任何将来的访问。

        复制代码
        1 // 当满足一种条件时,再去创建orders对象
        2 if (displayOrders == true)
        3 {
        4     DisplayOrders(_orders.Value.OrderData);
        5 }
        6 else
        7 {
        8     // Don't waste resources getting order data.
        9 }
        复制代码

        线程安全初始化

        默认情况下,Lazy<(Of <(T>)>) 对象是线程安全的。 这意味着如果构造函数未指定线程安全性的类型,它创建的 Lazy<(Of <(T>)>) 对象都是线程安全的。 在多线程方案中,要访问线程安全的 Lazy<(Of <(T>)>) 对象的 Value 属性的第一个线程将为所有线程上的所有后续访问初始化该对象,并且所有线程都共享相同数据。 因此,由哪个线程初始化对象并不重要,争用条件将是良性的。

        复制代码
         1 // Initialize the integer to the managed thread id of the 
         2 // first thread that accesses the Value property.
         3 Lazy<int> number = new Lazy<int>(() => 
         4      Thread.CurrentThread.ManagedThreadId);
         5 
         6 Thread t1 = new Thread(() => 
         7     Console.WriteLine("number on t1 = {0} ThreadID = {1}",
         8                       number.Value, Thread.CurrentThread.ManagedThreadId));
         9 t1.Start();
        10 
        11 Thread t2 = new Thread(() => 
        12     Console.WriteLine("number on t2 = {0} ThreadID = {1}",
        13                       number.Value, Thread.CurrentThread.ManagedThreadId));
        14 t2.Start();
        15 
        16 Thread t3 = new Thread(() => 
        17     Console.WriteLine("number on t3 = {0} ThreadID = {1}", number.Value,
        18                       Thread.CurrentThread.ManagedThreadId));
        19 t3.Start();
        20 
        21 // Ensure that thread IDs are not recycled if the 
        22 // first thread completes before the last one starts.
        23 t1.Join();
        24 t2.Join();
        25 t3.Join();
        26 
        27 /* Sample Output:
        28     number on t1 = 11 ThreadID = 11
        29     number on t3 = 11 ThreadID = 13
        30     number on t2 = 11 ThreadID = 12
        31     Press any key to exit.
        32 */
        复制代码

        若要通过使用延迟初始化来实现一个公共属性,请将该属性的支持字段定义为 Lazy<(Of <(T>)>) 对象,并从该属性的 get 访问器返回 Value 属性。

        复制代码
         1 class Customer
         2 {
         3     private Lazy<Orders> _orders;
         4     public string CustomerID {get; private set;}
         5     public Customer(string id)
         6     {
         7         CustomerID = id;
         8         _orders = new Lazy<Orders>(() =>
         9         {
        10             // You can specify any additonal 
        11             // initialization steps here(这个Orders不会应该Customer的实例化,而被实例化,它只会在使时,才会被实例化)
        12             return new Orders(this.CustomerID);
        13         });
        14     }
        15 
        16     public Orders MyOrders
        17     {
        18         get
        19         {
        20             // Orders is created on first access here.
        21             return _orders.Value;
        22         }
        23     }
        24 }
        复制代码

        延时实例化,在大对象时使用比较多,使用Lazy<(Of <(T>)>)我们还可以实现一种泛型的单例基类,看代码:

        复制代码
         1  /// <summary>
         2     /// 泛型单例基类
         3     /// </summary>
         4     public abstract class Singleton<TEntity> where TEntity : class
         5     {
         6         private static readonly Lazy<TEntity> _instance
         7           = new Lazy<TEntity>(() =>
         8           {
         9               var ctors = typeof(TEntity).GetConstructors(
        10                   BindingFlags.Instance
        11                   | BindingFlags.NonPublic
        12                   | BindingFlags.Public);
        13               if (ctors.Count() != 1)
        14                   throw new InvalidOperationException(String.Format("Type {0} must have exactly one constructor.", typeof(TEntity)));
        15               var ctor = ctors.SingleOrDefault(c => c.GetParameters().Count() == 0 && c.IsPrivate);
        16               if (ctor == null)
        17                   throw new InvalidOperationException(String.Format("The constructor for {0} must be private and take no parameters.", typeof(TEntity)));
        18               return (TEntity)ctor.Invoke(null);
        19           });
        20 
        21         public static TEntity Instance
        22         {
        23             get { return _instance.Value; }
        24         }
        25     }
        复制代码

         

        参考 文献:

        http://technet.microsoft.com/zh-cn/magazine/dd997286%28VS.95%29.aspx

        http://www.fascinatedwithsoftware.com/blog/post/2011/07/13/A-Generic-Singleton-Class.aspx

         

        返回目录  基础才是重中之重系列~目录(永久更新中)

  • 相关阅读:
    网页图表Highcharts实践教程标之添加题副标题版权信息
    S3C6410 裸机硬件JPEG解码(转)
    FPGA UART简单的串口接收模块
    unicode转GBK,GNK转unicode,解决FATFS中文码表占用ROM问题(转)
    Java 基础类型转换byte数组, byte数组转换基础类型
    JNI错误总结(转)
    Java通过JNI调用dll详细过程(转)
    UDP传输包大小(转)
    SD卡兼容性问题(转)
    汉字与区位码互转(转)
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2546259.html
Copyright © 2020-2023  润新知