.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 = new LazySingleton();
    }
}
 

.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; }

以上
● 通过私有构造函数屏蔽了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();
        }
    }

延迟加载的本质大致是:

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

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

".NET泛型"系列包括:

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

.NET泛型02,泛型的使用

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

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

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

时间: 2024-11-10 07:26:29

.NET泛型04,使用Lazy<T>实现延迟加载的相关文章

jQuery Lazy Load 图片延迟加载

基于 jQuery 的图片延迟加载插件,在用户滚动页面到图片之后才进行加载. 对于有较多的图片的网页,使用图片延迟加载,能有效的提高页面加载速度. 版本: jQuery v1.4.4+ jQuery Lazy Load v1.7.2 注意事项: 需要真正实现图片延迟加载,必须将真实图片地址写在 data-original 属性中.若 src 与 data-original 相同,则只是一个特效而已,并不达到延迟加载的功能. 载入 JavaScript 文件 <script src="jqu

单例模式 Lazy 按需延迟加载

在我们刚学设计模式的时候,单例模式可能是设计模式中最简单最容理解的吧.今天我们就来探究他不一样的风格,不一样的单例模式 首先,我们来看一下通俗的单例模式的设计 public class Person { //这里必须要写私有构造函数 private Person() { } public string Name { get; set; } public string Age { get; set; } private static object obj = new object(); priva

使用Lazy&lt;T&gt;实现对客户订单的延迟加载

"延迟加载"是指在需要的时候再加载数据.比如获得一个Customer信息,并不会把该Customer的Orders信息一下加载出来,当需要显示Orders的时候再加载.简单来说,就是按需加载.使用"延迟加载"的好处是减少应用程序响应时间,降低内存消耗,避免不必要的数据库交互. □ 即时加载 创建Order类和Customer类,Customer中维护着Order的一个集合,在Customer的构造函数中给Order集合赋值.即,只要创建Customer实例,就会加载

Hibernate的延迟加载 ,懒加载,lazy

Hibernate延迟加载有很多配置方法,本文主要说明几种常用的配置方法,以及在Session的get()和load()方法,Query对象的iterator()和list()方法中的效果.下面是本例用到的两张表.实体类和配置信息: Company表: Employee表(employee_company_id为外键) Company实体类: import java.util.Set; public class Company {    private int companyId;    pri

懒加载(延迟加载)

懒加载FatchType.LAZY也称为延迟加载,是Hibernate3关联关系对象默认的加载方式,所谓懒加载就是当在真正需要数据的时候,才真正执行数据加载操作.简单理解为,只有在使用的时候,才会发出sql语句进行查询.懒加载的有效期是在session打开的情况下,当session关闭后,会报异常.当调用load方法加载对象时,返回代理对象,等到真正用到对象的内容时才发出sql语句. 急加载FatchType.EAGER 也成为立即加载,时立即执行sql语句.在session没有关闭的之前,如果

解密Lazy&lt;T&gt;

1.Lazy<T>的使用 无意间看到一段代码,在创建对象的时候使用了Lazy,顾名思义Lazy肯定是延迟加载,那么它具体是如何创建对象,什么时候创建对象了? 先看这段示列代码: public class OrderController : Controller { private readonly Lazy<OrderService> _orderSrv = new Lazy<OrderService>(); public ActionResult CreateOrde

04.Hibernate一对一关联

前言:本文主要介绍使用Hibernate映射一对一的关联关系的两种方式:使用外键映射.使用主键映射. 1.数据库表的一对一关联关系 本文根据客户信息表(tb_customer)和地址信息表(tb_address)来说明其一对一的关系,每一个客户都有一个家庭住址,而每一个地址都对应一个客户. (1)使用外键映射的数据库表说明 数据库表模型图如下: 数据库建表语句如下: CREATE TABLE tb_customer ( id bigint NOT NULL auto_increment COMM

JavaScript 延迟加载

本文转载自:http://blog.csdn.net/m13666368773/article/details/7586106 一.延迟加载(lazy loading) 延迟加载:有些 js 代码并不是页面初始化的时候就立刻需要的,而稍后的某些情况才需要的.延迟加载就是一开始并不加载这些暂时不用的js,而是在需要的时候或稍后再通过js 的控制来异步加载. 也就是将 js 切分成许多模块,页面初始化时只加载需要立即执行的 js ,然后其它 js 的加载延迟到第一次需要用到的时候再加载. 特别是页面

hibernate manytoone中的lazy EAGER

Hibernate中的字段映射中的Fetch有两种方式:EAGER和LAZY Eager:全部抓取 Lazy:延迟抓取 如果在字段中声明为Eager,那么在取得当前Bean时,同时会抓取Bean中的关联Bean值.即数据库查询多次.反之Lazy则在之后抓取提交查询. 比如,有如下声明为Eager的User Bean: @OneToMany(mappedBy="user", cascade=CascadeType.ALL, fetch=FetchType.EAGER) private S