".NET泛型"系列:
ASP.NET泛型一之泛型简介与基本语法
ASP.NET泛型二之泛型的使用方法
ASP.NET泛型三之使用协变和逆变实现类型转换
ASP.NET泛型四之使用Lazy<T>实现延迟加载
对于一些"大对象"的创建,我们常常希望延迟加载,即在需要的时候再创建对象实例。现在Lazy<T>很好地支持了这一特点。主要包括:
没有Lazy<T>之前
在没有Lazy<T>之前,我们通过如下方式实现延迟加载。
public class LazySinleton
{
private LazySingleton()
{}
public static LazySingleton Instance
{
get
{
return Lazy.data;
}
}
private class Lazy
{
static Lazy()
{}
internal static readonly LazySingleton data = new LazySingleton();
}
}
以上
- 通过私有构造函数屏蔽了LazySingleton类通过构造函数创建的方式
- 私有嵌套类Lazy的data字段负责提供一个LazySingleton的实例
- 只能通过LazySingleton的属性Instance,才能拿到内部类Lazy.data所代表的实例
Lazy<T>实例
先看Lazy<T>的定义:
public class Lazy<T>
{
public Lazy();
public Lazy(bool isThreadSafe);
public Lazy(Func<T> valueFactory);
public Lazy(LazyThreadSafeMode mode);
public Lazy(Func<T> valueFactory, bool isThreadSafe);
public Lazy(Funct<T> valueFactory, LazyThreadSafetyMode mode);
public bool IsValueCreated{get;}
public T Value {get;}
public override string ToStirng();
}
通过Lazy<T>的构造函数重载创建对象,再通过体现延迟加载的Value属性来实现对象的创建,并获取对象实例。
public class SomeClass
{
public int ID{get;set;}
}
Lazy<SomeClass> temp = new Lazy<SomeClass>();
Console.WriteLine(temp.Value.ID);
以上,只适用于没有构造函数的情况,如果有构造函数如何处理呢?
--使用public Lazy(Func<T> valueFactory),通过委托创建对象
pubic class SomeClass
{
public int ID{get;set;}
public SomeClass(int id)
{
this.ID = id;
}
}
Lazy<SomeClass> temp = new Lazy<SomeClass>(() => new Big(100));
Console.WriteLine(temp.Value.ID);
延迟加载的本质
创建自定义延迟加载类。
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;
}
}
}
自定义带构造函数的类。
public class Big
{
public int ID { get; set; }
public Big(int id)
{
this.ID = id;
}
}
自定义创建对象实例的工厂类。
public class BigFactory
{
public static Big Build()
{
return new Big(10);
}
}
客户端调用。
class Program
{
static void Main(string[] args)
{
MyLazy<Big> temp = new MyLazy<Big>(() => BigFactory.Build());
Console.WriteLine(temp.Value.ID);
Console.ReadKey();
}
}
延迟加载的本质大致是:
- 由延迟加载类的内部嵌套类产生对象实例
- 再通过延迟加载类的某个属性来延迟获取对象实例,而对象实例是通过委托等方式创建的