对于一些"大对象"的创建,我们常常希望延迟加载,即在需要的时候再创建对象实例。现在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>实现延迟加载的更多相关文章

  1. Lazy Load 图片延迟加载(转)

    jQuery Lazy Load 图片延迟加载来源 基于 jQuery 的图片延迟加载插件,在用户滚动页面到图片之后才进行加载. 对于有较多的图片的网页,使用图片延迟加载,能有效的提高页面加载速度. ...

  2. jQuery Lazy Load 图片延迟加载

    基于 jQuery 的图片延迟加载插件,在用户滚动页面到图片之后才进行加载. 对于有较多的图片的网页,使用图片延迟加载,能有效的提高页面加载速度. 版本: jQuery v1.4.4+ jQuery ...

  3. lazy load 图片延迟加载 跟随滚动条

    http://plugins.jquery.com/lazyload/ Jquery.LazyLoad.js插件参数详解: 1,用图片提前占位 placeholder : "img/grey ...

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

    协变(Convariant)和逆变(Contravariant)的出现,使数组.委托.泛型类型的隐式转换变得可能. 子类转换成基类,称之为协变:基类转换成子类,称之为逆变..NET4.0以来,支持了泛 ...

  5. .NET泛型02,泛型的使用

    在" .NET泛型01,为什么需要泛型,泛型基本语法"中,了解了泛型的基本概念,本篇偏重于泛型的使用.主要包括: ■ 泛型方法重载需要注意的问题■ 泛型的类型推断■ 泛型方法也可以 ...

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

    .NET泛型或许是借鉴于C++泛型模版,借助它可以实现对类型的抽象化.泛型处理,实现了类型和方法之间的解耦.一个最经典的运用是在三层架构中,针对不同的领域模型,在基接口.基类中实现针对各个领域模型的泛 ...

  7. jQuery延迟加载插件(Lazy Load)详解

    最 新版本的Lazy Load并不能替代你的网页.即便你使用JavaScript移除了图片的src属性,有些现代的浏览器仍然会加载图片.现在你必须修改你的html代 码,使用占位图片作为img标签的s ...

  8. 使用Lazy<T>实现对客户订单的延迟加载

    "延迟加载"是指在需要的时候再加载数据.比如获得一个Customer信息,并不会把该Customer的Orders信息一下加载出来,当需要显示Orders的时候再加载.简单来说,就 ...

  9. java:Hibernate框架4(延迟加载(lazy),抓取(fetch),一级缓存,get,load,list,iterate,clear,evict,flush,二级缓存,注解,乐观锁和悲观锁,两者的比较)

    1.延时加载和抓取: hibernate.cfg.xml: <?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE hibernate-co ...

随机推荐

  1. Linux学习笔记:pwd与dirs的区别

    在Linux中可以使用pwd和dirs进行当前目录查看,分别用于显示当前目录和显示完整目录记录.具体如下: 1.pwd 显示当前目录 2.dirs 显示目录堆叠中的记录 END 2018-08-21  ...

  2. return to dl_resolve无需leak内存实现利用

    之前在drop看过一篇文章,是西电的Bigtang师傅写的,这里来学习一下姿势做一些笔记. 0x01 基础知识 Linux ELF文件存在两个很重要的表,一个是got表(.got.plt)一个是plt ...

  3. html meta标签使用总结(转)

    之前学习前端中,对meta标签的了解仅仅只是这一句. <meta charset="UTF-8"> 但是打开任意的网站,其head标签内都有一列的meta标签.比如我博 ...

  4. CF475C. Kamal-ol-molk's Painting

    C. Kamal-ol-molk's Painting time limit per test 2 seconds memory limit per test 256 megabytes input ...

  5. USACO 6.3 Fence Rails(一道纯剪枝应用)

    Fence RailsBurch, Kolstad, and Schrijvers Farmer John is trying to erect a fence around part of his ...

  6. HDU - 1716 排列2 水题

    排列2 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submis ...

  7. Elasticsearch源码分析 | 单节点的启动和关闭

    本文主要简要介绍Elasticsearch单节点的启动和关闭流程.Elasticsearch版本:6.3.2 相关文章 1.Google Guice 快速入门 2.Elasticsearch 中的 G ...

  8. nginx安装第三方模块

    原已经安装好的nginx,现在需要添加一个未被编译安装的模块 举例说明:安装第三方的ngx_cache_purge模块(用于清除指定URL的缓存) nginx的模块是需要重新编译nginx,而不是像a ...

  9. Linux怎么开启ssh

    一.查看ssh开启状态 service ssh status 这是已经开启了的状态 二.如果没有开启  键入以下命令开启 service ssh start 三.开启后如果不能利用xshell远程访问 ...

  10. Vue-router浅析(二)

    一.导航守卫 经常在项目中,会对页面做一些权限控制,所以需要对路由变化做出处理,跳转或取消相应的路由. 导航:即路由发生变化.导航守卫即对路由变化做出处理.当然也分几种情况:对全局变化做处理.对&qu ...