本文共 4364 字,大约阅读时间需要 14 分钟。
概念:一个对象的延迟初始化(也称延迟实例化)意味着该对象的创建将会延迟至第一次使用该对象时。 延迟初始化主要用于提高性能,避免浪费计算,并减少程序内存要求。
以下是最常见的方案:
有一个对象的创建开销很大时,应用程序可能不会使用它。 例如,假定您在内存中有一个 Customer 对象,该对象的 Orders 属性返回一个 Orders 对象。 初始化 Orders 对象可能需要创建 Orders 对象的一个大数组(Orders[]),并可能需要数据库连接。 如果用户从不访问 Orders 属性,则没有理由使用系统内存或计算周期来创建 Orders 对象。 通过使用 Lazy<Orders> 将 Orders 对象声明为延迟初始化,可以避免在不使用该对象的情况下浪费系统资源。
有一个对象的创建开销很大,您想要将创建它的时间延迟到完成其他开销大的操作之后。 例如,假定您的应用程序在启动时加载若干个对象实例,但只有一些对象实例需要立即执行。 通过将不必要的对象的初始化延迟到已创建必要的对象之后,可以提高应用程序的启动性能。
尽管您可以编写自己的代码来执行迟缓初始化,但我们建议改用 类。 支持线程安全(在一个线程中创建实例后,对其它线也是共享的),并提供一致的异常传播策略。
基本语法:
1 LazyOrders=new Lazy ();
另外,还可以在 构造函数中传递一个委托,用于在创建时调用包装类的特定构造函数重载,并执行所需的任何其他初始化步骤,如以下示例中所示。
1 Lazy_orders = new Lazy (() => new Orders(OrderSorted.CreateDate)); //可以重载指定的构造函数,如用来实现一种排序规则
在创建 Lazy 对象之后,在第一次访问 实例的 属性之前,将不会创建 Orders 的实例。 在第一次访问包装类型时,将会创建并返回该包装类型,并将其存储起来以备任何将来的访问。
1 // 当满足一种条件时,再去创建orders对象2 if (displayOrders == true)3 {4 DisplayOrders(_orders.Value.OrderData);5 }6 else7 {8 // Don't waste resources getting order data.9 }
默认情况下, 对象是线程安全的。 这意味着如果构造函数未指定线程安全性的类型,它创建的 对象都是线程安全的。 在多线程方案中,要访问线程安全的 对象的 属性的第一个线程将为所有线程上的所有后续访问初始化该对象,并且所有线程都共享相同数据。 因此,由哪个线程初始化对象并不重要,争用条件将是良性的。
1 // Initialize the integer to the managed thread id of the 2 // first thread that accesses the Value property. 3 Lazy number = new Lazy (() => 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 = 1129 number on t3 = 11 ThreadID = 1330 number on t2 = 11 ThreadID = 1231 Press any key to exit.32 */
若要通过使用延迟初始化来实现一个公共属性,请将该属性的支持字段定义为 对象,并从该属性的 get 访问器返回 属性。
1 class Customer 2 { 3 private Lazy_orders; 4 public string CustomerID { get; private set;} 5 public Customer(string id) 6 { 7 CustomerID = id; 8 _orders = new Lazy (() => 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 MyOrders17 {18 get19 {20 // Orders is created on first access here.21 return _orders.Value;22 }23 }24 }
延时实例化,在大对象时使用比较多,使用Lazy<(Of <(T>)>)我们还可以实现一种泛型的单例基类,看代码:
1 ///2 /// 泛型单例基类 3 /// 4 public abstract class Singletonwhere TEntity : class 5 { 6 private static readonly Lazy _instance 7 = new Lazy (() => 8 { 9 var ctors = typeof(TEntity).GetConstructors(10 BindingFlags.Instance11 | BindingFlags.NonPublic12 | 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 Instance22 {23 get { return _instance.Value; }24 }25 }
本文转自博客园张占岭(仓储大叔)的博客,原文链接:,如需转载请自行联系原博主。