参考
https://www.jb51.net/article/202143.htm
1. 什么是延迟初始化
延迟初始化
是一种将对象的创建延迟到第一次需要用时的技术,换句话说,对象的初始化是发生在真正需要的时候才执行。通过使用延迟初始化
技术,可以避免应用程序不必要的计算和内存消耗。
2. 简单使用场景
考虑下面两个类,Customer
和Order
,Customer
类包含了一个Orders
属性。一个人肯定会有很多的订单,也就意味着它可能包含了很多的数据,甚至还需要连接数据库去获取Orders
记录。在这种场景下,没必要给customer
集合中的所有人都带上完整的Orders
。因为这个初始化的开销
是巨大的,优化点就是在初始化不加载Orders
,直到某些customer
真的需要Orders
时才按需灌入。
3. 使用 System.Lazy
Lazy<IEnumerable<Order>> orders = new Lazy<IEnumerable<Order>>();
IEnumerable<Order> result = lazyOrders.Value;
现在,考虑下面的两个类:Author
和Blog
,一个作者可以写很多文章,所以这两个类之间是一对多
的关系,下面的代码片段展示了这种关系。
public class Author
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address { get; set; }
public List<Blog> Blogs { get; set; }
}
public class Blog
{
public int Id { get; set; }
public string Title { get; set; }
public DateTime PublicationDate { get; set; }
}
现在假定在用户界面
上仅需
展示Author
的基础信息,比如说:(firstname,lastname,address),在这种场景下,给Author
对象加载Blogs
集合是毫无意义的,当真的需要加载Blogs
时,执行Blogs.Value
即可立即执行,下面展示了Lazy<Blog> Blogs
的用法。
public class Author
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address { get; set; }
public Lazy<IList<Blog>> Blogs => new Lazy<IList<Blog>>(() => Author.GetBlogs(this.Id));
private static IList<Blog> GetBlogs(int Id)
{
//Write code here to retrieve all blog details for an author.
}
}
4. 使用Lazy实现单例模式
public sealed class StateManager
{
private StateManager()
{
}
public static StateManager Instance => Nested.obj;
private class Nested
{
static Nested()
{
}
internal static readonly StateManager obj = new StateManager();
}
}
5. System.Lazy
- 默认设置下,Lazy 类的所有公共和受保护的成员都是线程安全的,可从多个线程同时使用。
5.1 构造函数
- public Lazy ();
延迟初始化发生时,对应类型的无参构造被调用。
void Main()
{
var lazy = new Lazy<A>();
Console.WriteLine("================");
Console.WriteLine(lazy.Value.ToString());
}
class A
{
public A()
{
Console.WriteLine("A: Constructor");
}
public override string ToString()
{
return nameof(A) + ":" + nameof(ToString);
}
}
================
A: Constructor
A:ToString
- public Lazy (bool isThreadSafe);
延迟初始化发生时,对应类型的无参构造与指定的模式被调用。
isThreadSafe = true
创建的实例是线程安全的
isThreadSafe = false
创建的实例是非线程安全的 - Lazy(Func)
延迟初始化发生时,使用指定的方法进行初始化。
void Main()
{
var lazy = new Lazy<A>(CreateA);
Console.WriteLine("================");
Console.WriteLine(lazy.Value.ToString());
}
static A CreateA()
{
Console.WriteLine(nameof(CreateA));
return new A();
}
class A
{
public A()
{
Console.WriteLine("A: Constructor");
}
public override string ToString()
{
return nameof(A) + ":" + nameof(ToString);
}
}
================
CreateA
A: Constructor
A:ToString
- public Lazy (System.Threading.LazyThreadSafetyMode mode);
延迟初始化发生时,使用指定的线程安全枚举值进行初始化。
5.2 属性
- IsValueCreated 指示真实初始化是否发生
void Main()
{
var lazy = new Lazy<A>();
Console.WriteLine(nameof(lazy.IsValueCreated) + ": " + lazy.IsValueCreated);
Console.WriteLine("================");
Console.WriteLine(lazy.Value.ToString());
Console.WriteLine(nameof(lazy.IsValueCreated) + ": " + lazy.IsValueCreated);
}
class A
{
public A()
{
Console.WriteLine("A: Constructor");
}
public override string ToString()
{
return nameof(A) + ":" + nameof(ToString);
}
}
IsValueCreated: False
================
A: Constructor
A:ToString
IsValueCreated: True
- Value 获取真实类型的值
6. 自定义实现延迟加载
void Main()
{
var person = new Person();
Console.WriteLine("+++++++++++++++++++++++");
foreach (var phone in person.Phones)
{
Console.WriteLine(phone.ToString());
}
Console.WriteLine();
var personLazy = new PersonLazy();
Console.WriteLine("+++++++++++++++++++++++");
Console.WriteLine("调用属性");
var phones = personLazy.Phones;
Console.WriteLine("+++++++++++++++++++++++");
Console.WriteLine("执行属性");
foreach (var phone in personLazy.Phones())
{
Console.WriteLine(phone.ToString());
}
}
class Person
{
public List<Phone> Phones {get;set;} = new List<Phone>();
public Person()
{
System.Console.WriteLine(nameof(Person) + " is created.");
Console.WriteLine("+++++++++++++++++++++++");
this.Phones.Add(new Phone(){ID = "11111111111111"});
this.Phones.Add(new Phone(){ID = "22222222222222"});
this.Phones.Add(new Phone(){ID = "33333333333333"});
this.Phones.Add(new Phone(){ID = "44444444444444"});
this.Phones.Add(new Phone(){ID = "55555555555555"});
}
}
class PersonLazy
{
private List<Phone> phones = new List<Phone>();
public Func<List<Phone>> Phones => GetPhones;
public PersonLazy()
{
System.Console.WriteLine(nameof(PersonLazy) + " is created.");
Console.WriteLine("+++++++++++++++++++++++");
}
private List<Phone> GetPhones()
{
var phones = new List<Phone>();
phones.Add(new Phone() { ID = "11111111111111" });
phones.Add(new Phone() { ID = "22222222222222" });
phones.Add(new Phone() { ID = "33333333333333" });
phones.Add(new Phone() { ID = "44444444444444" });
phones.Add(new Phone() { ID = "55555555555555" });
return phones;
}
}
class Phone
{
public string ID {get;set;}
public Phone()
{
System.Console.WriteLine(nameof(Phone) + " is created.");
}
public override string ToString()
{
return nameof(Phone) + ": " + this.ID;
}
}
Person is created.
+++++++++++++++++++++++
Phone is created.
Phone is created.
Phone is created.
Phone is created.
Phone is created.
+++++++++++++++++++++++
Phone: 11111111111111
Phone: 22222222222222
Phone: 33333333333333
Phone: 44444444444444
Phone: 55555555555555PersonLazy is created.
+++++++++++++++++++++++
+++++++++++++++++++++++
调用属性
+++++++++++++++++++++++
执行属性
Phone is created.
Phone is created.
Phone is created.
Phone is created.
Phone is created.
Phone: 11111111111111
Phone: 22222222222222
Phone: 33333333333333
Phone: 44444444444444
Phone: 55555555555555