首页 > 代码库 > .NET泛型04,使用Lazy<T>实现延迟加载

.NET泛型04,使用Lazy<T>实现延迟加载

对于一些"大对象"的创建,我们常常希望延迟加载,即在需要的时候再创建对象实例。现在Lazy<T>很好地支持了这一特点。主要包括:

 

  • 没有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 = http://www.mamicode.com/new LazySingleton();
    }
}
 
<style type="text/css">.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }</style>

以上
● 通过私有构造函数屏蔽了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 =http://www.mamicode.com/ 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();        }    }

 

延迟加载的本质大致是:

● 由延迟加载类的内部嵌套类产生对象实例
● 再通过延迟加载类的某个属性来延迟获取对象实例,而对象实例是通过委托等方式创建的

 

参考资料:
《你必须知道的.NET(第2版)》,作者王涛。

 

".NET泛型"系列包括:

.NET泛型01,为什么需要泛型,泛型基本语法

.NET泛型02,泛型的使用

.NET泛型03,泛型类型的转换,协变和逆变

.NET泛型04,使用Lazy<T>实现延迟加载