C#基础知识回顾---你不知道的Lazy<T>

    对象的创建方式,始终代表了软件工业的生产力方向,代表了先进软件技术发展的方向,也代表了广大程序开发者的集体智慧。以new的方式创建,通过工厂方法,利用IoC容器,都以不同的方式实现了活生生实例成员的创生。而本文所关注的Lazy<T>也是干这事儿的。不过,简单说来,Lazy<T>要实现的就是按“需”创建,而不是按时创建。

我们往往有这样的情景,一个关联对象的创建需要较大的开销,为了避免在每次运行时创建这种家伙,有一种聪明的办法叫做实现“懒对象”,或者延迟加载。.NET 4.0之前,实现懒对象的机制,需要开发者自己来实现与管理它的定义如下:

[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();
}

假设,我们有一个大块头:

public class Big
{
    public int ID { get; set; }

    // Other resources
}

从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提供的关注度实在不少,我们眼花缭乱了。

 郑重声明本文非原创……

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏深度学习之tensorflow实战篇

Python中的__init__()方法整理中(两种解释)

解释一:看懂了就不用看第二种了 __init__()方法是Python学习当中重要的基础知识,__init__()方法意义重大的原因有两个。第一个原因是在对...

5256
来自专栏分布式系统和大数据处理

四种简单的排序算法

我觉得如果想成为一名优秀的开发者,不仅要积极学习时下流行的新技术,比如WCF、Asp.Net MVC、AJAX等,熟练应用一些已经比较成熟的技术,比如Asp.N...

912
来自专栏大内老A

[原创]深入理解C# 3.x的新特性(3):从Delegate、Anonymous Method到Lambda Expression

在C#3.0中,引入了一些列新的特性,比如: Implicitly typed local variable, Extension method,Lambda ...

2048
来自专栏Java爬坑系列

【Java入门提高篇】Day1 抽象类

  基础部分内容差不多讲解完了,今天开始进入Java提高篇部分,这部分内容会比之前的内容复杂很多,希望大家做好心理准备,看不懂的部分可以多看两遍,仍不理解的部分...

1766
来自专栏大内老A

深入理解C# 3.x的新特性(2):Extension Method[上篇]

在C#3.0中,引入了一些列新的特性,比如: Implicitly typed local variable, Extension method,Lambda ...

1856
来自专栏光变

你所不知道的Java之Integer

以下内容为作者辛苦原创,版权归作者所有,如转载演绎请在“光变”微信公众号留言申请,转载文章请在开始处显著标明出处。

1320
来自专栏me的随笔

抽象类 VS 接口

接口和抽象类是面向对象编程(OOP, Object Oriented programming)中两个绕不开的概念,二者相似而又有所不同。接下来,我们来了解二者的...

853
来自专栏小鄧子的技术博客专栏

为什么android API 中有很多对象的创建都是使用new关键字

首先,谢邀。 其次,是怎么找到我知乎账号的,我隐藏的这么深(脸红了) 最后,加入了自己的总结概括,让然也可以当成读书笔记来看。

743
来自专栏分布式系统和大数据处理

C#中的泛型

.Net 1.1版本最受诟病的一个缺陷就是没有提供对泛型的支持。通过使用泛型,我们可以极大地提高代码的重用度,同时还可以获得强类型的支持,避免了隐式的装箱、拆箱...

887
来自专栏walterlv - 吕毅的博客

.NET/C# 判断某个类是否是泛型类型或泛型接口的子类型

2018-09-01 08:28

652

扫码关注云+社区