​​回到目录​​

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

以下是最常见的方案:

  • 有一个对象的创建开销很大时,应用程序可能不会使用它。 例如,假定您在内存中有一个 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​

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

作者:仓储大叔,张占岭,
荣誉:微软MVP