[你必须知道的.NET]第三十三回,深入.NET 4.0之,Lazy<T>点滴
发布日期:2009.10.29 作者:Anytao
© 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处。
对象的创建方式,始终代表了软件工业的生产力方向,代表了先进软件技术发展的方向,也代表了广大程序开发者的集体智慧。以new的方式创建,通过工厂方法,利用IoC容器,都以不同的方式实现了活生生实例成员的创生。而本文所关注的Lazy<T>也是干这事儿的。不过,简单说来,Lazy<T>要实现的就是按“需”创建,而不是按时创建。
我们往往有这样的情景,一个关联对象的创建需要较大的开销,为了避免在每次运行时创建这种家伙,有一种聪明的办法叫做实现“懒对象”,或者延迟加载。.NET 4.0之前,实现懒对象的机制,需要开发者自己来实现与管理,例如,你可以翻开老赵同志的较为理想的延迟代理的编写方式一文来了解其原理和场合。可喜的是,在.NET 4.0中包含的另一个好玩的家伙System.Lazy<T>。它的定义如下:
[Serializable]
public class Lazy<T>
{
public Lazy();
public Lazy(bool isThreadSafe);
public Lazy(Func<T> valueFactory);
public Lazy(Func<T> valueFactory, bool isThreadSafe); public bool IsValueCreated { get; }
public T Value { get; } public override string ToString();
}
注:VS2010 Beta2对Lazy<T>和VS2010 Beta1有较大差异,因此本文仅以最新版本为标准,并不保证最终.NET 4.0正式版的实际情况。
假设,我们有一个大块头:
public class Big
{
public int ID { get; set; } // Other resources
}
那么,可以使用如下的方式来实现Big的延迟创建:
static void Main(string[] args)
{
Lazy<Big> lazyBig = new Lazy<Big>();
}
从Lazy<T>的定义可知,其Value属性就是我们包装在Lazy Wrapper中的真实Big对象,那么当我们第一次访问lazyBig.Value时,就回自动的创建Big实例。
static void Main(string[] args)
{
Lazy<Big> lazyBig = new Lazy<Big>(); Console.WriteLine(lazyBig.Value.ID);
}
当然,有其定义可知,Lazy远没有这么小儿科,它同时还可以为我们提供以下的服务:
- 通过IsValueCreated,获取是否“已经”创建了实例对象。
- 解决非默认构造函数问题。
显而易见。我们的Big类并没有提供带参数构造函数,那么如下的Big类:
public class Big
{
public Big(int id)
{
this.ID = id;
} public int ID { get; set; } // Other resources
}
上述创建方式将引发运行时异常,提示包装对象没有无参的构造函数。那么,这种情形下的延迟加载,该如何应对呢?其实Lazy<T>的构造中还包括:
public Lazy(Func<T> valueFactory);
它正是用来应对这样的挑战:
static void Main(string[] args)
{
// Lazy<Big> lazyBig = new Lazy<Big>();
Lazy<Big> lazyBig = new Lazy<Big>(() => new Big(100)); Console.WriteLine(lazyBig.Value.ID);
}
其实,从public Lazy(Func<T> valueFactory)的定义可知,valueFactory可以返回任意的T实例,那么任何复杂的构造函数,对象工厂或者IoC容器方式都可以在此以轻松的方式兼容,例如:
public class BigFactory
{
public static Big Build()
{
return new Big(100);
}
}
可以应用Lazy<T>和BigFactory实现Big的延迟加载:
static void Main(string[] args)
{
Lazy<Big> lazyBig = new Lazy<Big>(() => BigFactory.Build()); Console.WriteLine(lazyBig.Value.ID);
}
- 提供多线程环境支持。
另外的构造器:
public Lazy(bool isThreadSafe);
public Lazy(Func<T> valueFactory, bool isThreadSafe);
中,isThreadSafe则应用于多线程环境下,如果isThreadSafe为false,那么延迟加载对象则一次只能创建于一个线程。
关于Lazy<T>的应用,其实已经不是一个纯粹的语言问题,还涉及了对设计的考量,例如实现整个对象的延迟加载,或者实现延迟属性,考量线程安全等等。既然是点滴,就不说教太多。因为,.NET 4.0提供的关注度实在不少,我们眼花缭乱了。
参考文献
- Lazy Initialization, http://msdn.microsoft.com/en-us/library/dd997286(VS.100).aspx
更多闲言碎语,关注anytao.net
[你必须知道的.NET]第三十三回,深入.NET 4.0之,Lazy<T>点滴的更多相关文章
- [你必须知道的.NET]第三十一回,深入.NET 4.0之,从“新”展望
发布日期:2009.05.22 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. /// <summary> /// 本文开始,将以& ...
- [你必须知道的.NET]第三十回:.NET十年(下)
发布日期:2009.05.11 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. /// <summary> /// 本文部分内容,已 ...
- [你必须知道的.NET]第三十五回,判断dll是debug还是release,这是个问题
发布日期:2009.12.29 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. 问题的提出 晚上翻着群里的聊天,发现一个有趣的问题:如何通过编码 ...
- [你必须知道的.NET]第二十四回:认识元数据和IL(上)
发布日期:2009.02.24 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. 说在,开篇之前 很早就有说说Metadata(元数据)和IL(中 ...
- [你必须知道的.NET]第二十五回:认识元数据和IL(中)
发布日期:2009.02.25 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. 说在,开篇之前 书接上回[第二十四回:认识元数据和IL(上)], ...
- [你必须知道的.NET]第二十九回:.NET十年(上)
发布日期:2009.05.08 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. /// <summary> /// 本文部分内容,已 ...
- [你必须知道的.NET]第二十六回:认识元数据和IL(下)
发布日期:2009.03.04 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. 说在,开篇之前 书接上回: 第二十四回:认识元数据和IL(上), ...
- [你必须知道的.NET]第三十二回,,深入.NET 4.0之,Tuple一二
发布日期:2009.06.01 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. Tuple,是函数式编程的概念之一,早见于Elang.F#等动态 ...
- [你必须知道的.NET]第三十四回,object成员,不见了!
发布日期:2009.10.30 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. 在.NET世界了,object是公认的造物主,其麾下的7大成员, ...
随机推荐
- Android判断当前的android设备是否处于联网状态
首先,要想获得当前android设备是否处于联网状态,那么android本身给我们提供了一个服务 private ConnectivityManager connectivityManager;//用 ...
- [译]rabbitmq 2.1 Consumers and producers (not an economics lesson)
我对rabbitmq学习还不深入,这些翻译仅仅做资料保存,希望不要误导大家. For now, all you need to know is that producers create messag ...
- [原]Java修炼 之 基础篇(一)Java语言特性
学习软件开发,首先要选择的就是选择需要采用的编程语言,考虑语言本身的优缺点和实际需求,综合评价之后选择相关的语言进行系统开发.本篇博客开始就从近年来比较流行的Java开始为大家讲起. 背景 1995年 ...
- JSP的7个动作指令
动作指令与编译指令不同,编译指令是通知Servlet引擎的处理信息,而动作指令知识运行时的动作.编译指令在将JSP编译成Servlet时起作用,而处理指令通常可替换成JSP脚本,它知识JSP脚本的标准 ...
- java implement
接口不能被实例化,但是可以声明一个接口类型的变量. eg. A implements B,则可以有B variableName = new A(),这和extends的用法是类似的 接口可被认为是纯抽 ...
- UIImageView swift
// // ViewController.swift // UILabelTest // // Created by mac on 15/6/23. // Copyright (c) 2015年 fa ...
- [SSH服务]——SSH端口转发
实验拓扑图 实验描述 假设有三台主机A.B.C.B和A.C可以连通,AC两台主机不能连通. 这时候可以用本地端口转发,来实现A和C通过B来连通. 实验中,为了构造上述环境,我们使用三台虚拟机,其网络环 ...
- [uwp开发]数据绑定那些事(1)
现在是msp候选人,是时候写点技术博客来加分了(实则是个人的心得体会). 注:以下都是个人理解,错误在所难免,欢迎批评指正 以前接触过WPF,只会简单的一些操作,现在在逐渐学习UWP(Universa ...
- Ant学习---第五节:Ant_Junit介绍(基于3的版本)
Junit3 和 Junit4 有本质上的区别 1.普通java类,代码如下: package learn.junit; public class HelloWorld { public String ...
- java笔试题(1)
char型变量中能不能存贮一个中文汉字? char型变量是用来存储Unicode编码的字符的,unicode编码字符集中包含了汉字,所以,char型变量中当然可以存储汉字啦.不过,如果某个特殊的汉字没 ...