.NET Lazy懒加载Demo(技术拓展)
最新在朋友那里看到有问这个Lazy是干什么用的,深思熟虑以后决定写一篇记录博客,记录以往的学习成果-
概念:延时加载(延时实例化或延时初始化)重点是延时,用时加载。意思是对象在使用的时候创建而不是在实例化的的时候才创建。
延时加载主要应用的场景:
1:数据层(ADO.NET或Entity Framework等ORM,Java里面的Hibernate也用到了这种技术)
2:反射(加载Assemblier,Type,MEF)
3:缓存对象,领域实体
4:解决.Net依赖注入或者Core依赖注入的循环依赖注入导致的异常问题
当然,我们目前用到延时最多的场景想必就是EF或者EF Core,我们在使用的时候声明上下文,通过委托表达式来筛选条件,在最后的时候我们会用上一个Tolist();调试过得人应该都知道,只有在ToList()的时候数据才会真正的从数据库查询出来,在此之前一切都是铺垫。
如下:
DbContext db=new DbContext ();
var Data=db.表明(实体).条件.ToList();
同理:Lazy也如此去理解,但是使用范围相当广泛,在此就列举基本的使用方法和封装方法,如下:
首先我们来测试Lazy的周期是否符合我们的理论观点:
Test类中CWTest是测试方法,本文所有Test均是如下图意思
官方提供的方法重载如下:
有很多重载:
1:委托创建对象
2:判断是否线程安全:
3:获取目前存在的县城信息:
4:以及针对某个委托的创建的实例是否线程安全
5:某委托创建的线程模型信息
其他扩展:
1:判断是否创建成功:
2:创建的实例返回
使用方法1:
运行后:
我们看到在Lazy声明时,我们的实例在内存中是不存在的,
在Way1.Value.CWTest();调用后,我们才检索到我们的实例
使用方法2:
运行后:
与第一种区别不大,周期依然符合理论
使用方法3:
运行后:
我们通过拉姆达表达式去New一个实例并返回给Lazy的泛型重载,
周期依然符合理论
使用方法4:
通过工厂,在工厂内部动态的调用待创建的实例并进行Build返回给业务层。
/// <summary>
/// 自定义封装懒加载
/// </summary>
/// <typeparam name="T"></typeparam>
public class MyLazy<T>
{
private volatile object boxed; //volatile说明在多线程状况下,也可以修改该字段
private Func<T> valueFactory; //委托,用来生产T对象实例
static MyLazy() { }
public MyLazy() { }
public MyLazy(Func<T> valueFactory)
{
this.valueFactory = valueFactory;
}
public T Value
{
get
{
Boxed boxed = null;
if (this.boxed != null)
{
boxed = this.boxed as Boxed;
if (boxed != null)
{
return boxed.value;
}
}
return this.Init();
}
}
//初始化对象实例
private T Init()
{
Boxed boxed = null;
if (this.boxed == null)
{
boxed = this.CreateValue();
this.boxed = boxed;
}
return boxed.value;
}
//创建内部类实例
private Boxed CreateValue()
{
//如果创建对象实例的委托valueFactory存在
if (this.valueFactory != null)
{
//就通过委托生成对象实例
return new Boxed(this.valueFactory());
}
else
{
//否则,通过反射生成对象实例
return new Boxed((T)Activator.CreateInstance(typeof(T)));
}
}
//内部嵌套类,通过构造函数对其字段赋值
private class Boxed
{
internal T value;
internal Boxed(T value)
{
this.value = value;
}
}
}
运行后:
结果依然符合我们的理论逻辑,以上就是Lazy懒加载(实例延时声明的基本使用扩展)
文章内容有待大神进行指点,虚心请教!