简介 从net 4.0开始,C#开始支持延迟初始化,通过Lazy关键字,我们可以声明某个对象为仅仅当第一次使用的时候,再初始化,如果一直没有调用,那就不初始化,省去了一部分不必要的开销,提升了效率,同时Lazy是天生线程安全的
应用场景
例如,假定内存中有具有 Orders 属性的 Customer 对象,该对象包含大量 Order 对象,初始化这些对象需要数据库连接。 如果用户 永远不要求显示 Orders 或在计算中使用该数据,则无需使用系统内存或计算周期来创建它。 通过使用 Lazy 来声明 Orders 对象用 于迟缓初始化,可以避免在不使用该对象时浪费系统资源。
对象创建成本高,且希望将其创建推迟到其他高成本操作完成后。
例如,假定程序在启动时加载多个对象实例,但是只需立即加载其中一部分。 可以通过推迟初始化不需要的对象,直到创建所需对 象,提升程序的启动性能。
基本用法 方式一:使用默认的构造函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 using System;namespace LazyUsage { class LazyDemo { static void Main () { Lazy<Data> lazyData = new Lazy<Data>(); Console.WriteLine("Main->is lazyData Initialized? value = " + lazyData.IsValueCreated); lazyData.Value.Print(); Console.WriteLine("Main->is lazyData Initialized? value = " + lazyData.IsValueCreated); Console.ReadKey(); } } class Data { public Data () { Console.WriteLine("Data::.ctor->Initialized" ); } public void Print () { Console.WriteLine("Data::Print->println" ); } } }
输出结果
1 2 3 4 Main->is lazyData Initialized? value = False Data::.ctor->Initialized Data::Print->println Main->is lazyData Initialized? value = True
方式二:使用Func委托返回指定的构造函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 using System;namespace LazyUsage { class LazyDemo { static void Main () { Lazy<Data> lazyData = new Lazy<Data>( () => { Console.WriteLine("Main->lazyData will be Initialized!" ); return new Data("Test" ); }); Console.WriteLine("Main->is lazyData Initialized? value = " + lazyData.IsValueCreated); lazyData.Value.Print(); Console.WriteLine("Main->is lazyData Initialized? value = " + lazyData.IsValueCreated); Console.ReadKey(); } } class Data { public string Name { get ; private set ; } public Data (string name ) { Name = name; Console.WriteLine("Data::.ctor->Initialized,name = " +name); } public void Print () { Console.WriteLine("Data::Print->name = " + Name); } } }
输出结果
1 2 3 4 5 Main->is lazyData Initialized? value = False Main->lazyData will be Initialized! Data::.ctor->Initialized,name = Test Data::Print->name = Test Main->is lazyData Initialized? value = True
关于Lazy.Value的使用 Lazy对象创建后,并不会立即创建对应的对象,只有在变量的Value属性被首次访问时才会真正的创建,同时会将其缓存到Value中,以便将来访问。
Value属性是只读的,也就意味着如果Value存储了引用类型,将无法为其分配新对象,只可以更改此对象公共的属性或者字段等,如果Value存储的是值类型,那么就不能修改其值了,只能通过再次调用变量的函数使用新的参数来创建新的变量
拓展 实现延迟属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Customer { private Lazy<Orders> _orders; public string CustomerID {get ; private set ;} public Customer (string id ) { CustomerID = id; _orders = new Lazy<Orders>(() => { return new Orders(this .CustomerID); }); } public Orders MyOrders { get { return _orders.Value; } } }
在实际使用中,Lazy类多声明为private甚至还要readonly
Value的属性是只读的,所以示例中只提供了Get的访问器,并未提供Set的访问器。
如果需要支持读取与写入属性的话,则Set访问器必须创建一个新的Lazy对象,同时必须编写自己的线程安全代码才能执行此操作